1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2023 The Khronos Group Inc.
6 * Copyright (c) 2023 Valve Corporation.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 *//*!
21 * \file
22 * \brief Fragment Shading Rate miscellaneous tests
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktFragmentShadingRateMiscTests.hpp"
26 #include "vktTestCaseUtil.hpp"
27
28 #include "vkImageUtil.hpp"
29 #include "vkObjUtil.hpp"
30 #include "vkCmdUtil.hpp"
31 #include "vkBarrierUtil.hpp"
32
33 #include "tcuImageCompare.hpp"
34
35 #include "deUniquePtr.hpp"
36
37 #include <sstream>
38 #include <vector>
39 #include <cstddef>
40
41 namespace vkt
42 {
43 namespace FragmentShadingRate
44 {
45
46 namespace
47 {
48
49 using namespace vk;
50
51 struct PositionColor
52 {
PositionColorvkt::FragmentShadingRate::__anon7d3bdfb20111::PositionColor53 PositionColor(const tcu::Vec4 &position_, const tcu::Vec4 &color_) : position(position_), color(color_)
54 {
55 }
56
57 tcu::Vec4 position;
58 tcu::Vec4 color;
59 };
60
getDefaultExtent(void)61 VkExtent3D getDefaultExtent(void)
62 {
63 return makeExtent3D(8u, 8u, 1u);
64 }
65
checkShadingRateSupport(Context & context,bool pipeline=false,bool primitive=false,bool attachment=false)66 void checkShadingRateSupport(Context &context, bool pipeline = false, bool primitive = false, bool attachment = false)
67 {
68 context.requireDeviceFunctionality("VK_KHR_fragment_shading_rate");
69 const auto &fsrFeatures = context.getFragmentShadingRateFeatures();
70
71 if (pipeline && !fsrFeatures.pipelineFragmentShadingRate)
72 TCU_THROW(NotSupportedError, "pipelineFragmentShadingRate not supported");
73
74 if (primitive && !fsrFeatures.primitiveFragmentShadingRate)
75 TCU_THROW(NotSupportedError, "primitiveFragmentShadingRate not supported");
76
77 if (attachment && !fsrFeatures.attachmentFragmentShadingRate)
78 TCU_THROW(NotSupportedError, "attachmentFragmentShadingRate not supported");
79 }
80
checkEnableDisableSupport(Context & context)81 void checkEnableDisableSupport(Context &context)
82 {
83 checkShadingRateSupport(context, true, false, true);
84 }
85
checkNoFragSupport(Context & context)86 void checkNoFragSupport(Context &context)
87 {
88 checkShadingRateSupport(context, true);
89 }
90
initDefaultVertShader(vk::SourceCollections & programCollection,const std::string & shaderName)91 void initDefaultVertShader(vk::SourceCollections &programCollection, const std::string &shaderName)
92 {
93 // Default vertex shader, including vertex color.
94 std::ostringstream vert;
95 vert << "#version 460\n"
96 << "#extension GL_EXT_fragment_shading_rate : enable\n"
97 << "layout (location=0) in vec4 inPos;\n"
98 << "layout (location=1) in vec4 inColor;\n"
99 << "layout (location=0) out vec4 outColor;\n"
100 << "void main (void) {\n"
101 << " gl_Position = inPos;\n"
102 << " outColor = inColor;\n"
103 << "}\n";
104 DE_ASSERT(!shaderName.empty());
105 programCollection.glslSources.add(shaderName) << glu::VertexSource(vert.str());
106 }
107
initDefaultFragShader(vk::SourceCollections & programCollection,const std::string & shaderName)108 void initDefaultFragShader(vk::SourceCollections &programCollection, const std::string &shaderName)
109 {
110 // Default fragment shader, with vertex color.
111 std::ostringstream frag;
112 frag << "#version 460\n"
113 << "layout (location=0) in vec4 inColor;\n"
114 << "layout (location=0) out vec4 outColor;\n"
115 << "void main (void) {\n"
116 << " outColor = inColor;\n"
117 << "}\n";
118 DE_ASSERT(!shaderName.empty());
119 programCollection.glslSources.add(shaderName) << glu::FragmentSource(frag.str());
120 }
121
initEnableDisableShaders(vk::SourceCollections & programCollection)122 void initEnableDisableShaders(vk::SourceCollections &programCollection)
123 {
124 initDefaultVertShader(programCollection, "vert");
125 initDefaultFragShader(programCollection, "frag");
126 }
127
initNoFragShaders(vk::SourceCollections & programCollection)128 void initNoFragShaders(vk::SourceCollections &programCollection)
129 {
130 initDefaultVertShader(programCollection, "vert");
131 }
132
getDefaultVertexInputStateCreateInfo(void)133 const VkPipelineVertexInputStateCreateInfo *getDefaultVertexInputStateCreateInfo(void)
134 {
135 static VkVertexInputBindingDescription vertexBinding = {
136 0u, // uint32_t binding;
137 static_cast<uint32_t>(sizeof(PositionColor)), // uint32_t stride;
138 VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate;
139 };
140
141 static VkVertexInputAttributeDescription inputAttributes[] = {
142 {
143 // position
144 0u, // uint32_t location;
145 0u, // uint32_t binding;
146 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
147 static_cast<uint32_t>(offsetof(PositionColor, position)), // uint32_t offset;
148 },
149 {
150 // color
151 1u, // uint32_t location;
152 0u, // uint32_t binding;
153 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
154 static_cast<uint32_t>(offsetof(PositionColor, color)), // uint32_t offset;
155 },
156 };
157
158 static const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = {
159 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
160 nullptr, // const void* pNext;
161 0u, // VkPipelineVertexInputStateCreateFlags flags;
162 1u, // uint32_t vertexBindingDescriptionCount;
163 &vertexBinding, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
164 static_cast<uint32_t>(de::arrayLength(inputAttributes)), // uint32_t vertexAttributeDescriptionCount;
165 inputAttributes, // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
166 };
167
168 return &vertexInputStateCreateInfo;
169 }
170
makeFragmentShadingRateStateCreateInfo(uint32_t width,uint32_t height,VkFragmentShadingRateCombinerOpKHR combiner0,VkFragmentShadingRateCombinerOpKHR combiner1)171 VkPipelineFragmentShadingRateStateCreateInfoKHR makeFragmentShadingRateStateCreateInfo(
172 uint32_t width, uint32_t height, VkFragmentShadingRateCombinerOpKHR combiner0,
173 VkFragmentShadingRateCombinerOpKHR combiner1)
174 {
175 const VkPipelineFragmentShadingRateStateCreateInfoKHR fragmentShadingRateStateCreateInfo = {
176 VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR, // VkStructureType sType;
177 nullptr, // const void* pNext;
178 makeExtent2D(width, height), // VkExtent2D fragmentSize;
179 {
180 // VkFragmentShadingRateCombinerOpKHR combinerOps[2];
181 combiner0,
182 combiner1,
183 },
184 };
185
186 return fragmentShadingRateStateCreateInfo;
187 }
188
189 // Test idea: draw with VRS enabled by a fragment shading rate attachment, then bind a pipeline with VRS disabled and draw again.
190 // This was being incorrectly handled in RADV. Ref: https://gitlab.freedesktop.org/mesa/mesa/-/issues/9005
testEnableDisable(Context & context)191 tcu::TestStatus testEnableDisable(Context &context)
192 {
193 const auto ctx = context.getContextCommonData();
194 const auto &fsrProperties = context.getFragmentShadingRateProperties();
195 const auto &minSize = fsrProperties.minFragmentShadingRateAttachmentTexelSize;
196 const auto &maxSize = fsrProperties.maxFragmentShadingRateAttachmentTexelSize;
197 const auto colorFormat = VK_FORMAT_R8G8B8A8_UNORM;
198 const auto colorUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
199 const auto colorSRR = makeDefaultImageSubresourceRange();
200 const auto colorSRL = makeDefaultImageSubresourceLayers();
201 const auto bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
202 const auto fsrFormat = VK_FORMAT_R8_UINT;
203 const auto fsrExtent = makeExtent3D(1u, 1u, 1u); // 1 pixel for the whole image.
204 const auto fsrUsage = (VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
205 const auto sampleCount = VK_SAMPLE_COUNT_1_BIT;
206
207 // Adjust image extent to an acceptable range so it's covered by a single FSR attachment pixel.
208 auto vkExtent = getDefaultExtent();
209 {
210 vkExtent.width = de::clamp(vkExtent.width, minSize.width, maxSize.width);
211 vkExtent.height = de::clamp(vkExtent.height, minSize.height, maxSize.height);
212 }
213 const tcu::IVec3 fbExtent(static_cast<int>(vkExtent.width), static_cast<int>(vkExtent.height),
214 static_cast<int>(vkExtent.depth));
215
216 vk::ImageWithBuffer colorBuffer(ctx.vkd, ctx.device, ctx.allocator, vkExtent, colorFormat, colorUsage,
217 VK_IMAGE_TYPE_2D);
218
219 // Fragment shading rate attachment.
220 const VkImageCreateInfo fsrAttachmentCreateInfo = {
221 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
222 nullptr, // const void* pNext;
223 0u, // VkImageCreateFlags flags;
224 VK_IMAGE_TYPE_2D, // VkImageType imageType;
225 fsrFormat, // VkFormat format;
226 fsrExtent, // VkExtent3D extent;
227 1u, // uint32_t mipLevels;
228 1u, // uint32_t arrayLayers;
229 sampleCount, // VkSampleCountFlagBits samples;
230 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
231 fsrUsage, // VkImageUsageFlags usage;
232 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
233 0u, // uint32_t queueFamilyIndexCount;
234 nullptr, // const uint32_t* pQueueFamilyIndices;
235 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
236 };
237 ImageWithMemory fsrAttachment(ctx.vkd, ctx.device, ctx.allocator, fsrAttachmentCreateInfo, MemoryRequirement::Any);
238 const auto fsrAttView =
239 makeImageView(ctx.vkd, ctx.device, fsrAttachment.get(), VK_IMAGE_VIEW_TYPE_2D, fsrFormat, colorSRR);
240
241 const auto &binaries = context.getBinaryCollection();
242 const auto vertModule = createShaderModule(ctx.vkd, ctx.device, binaries.get("vert"));
243 const auto fragModule = createShaderModule(ctx.vkd, ctx.device, binaries.get("frag"));
244
245 const std::vector<VkAttachmentDescription2> attachmentDescriptions{
246 // Color attachment.
247 {
248 VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2, // VkStructureType sType;
249 nullptr, // const void* pNext;
250 0u, // VkAttachmentDescriptionFlags flags;
251 colorFormat, // VkFormat format;
252 sampleCount, // VkSampleCountFlagBits samples;
253 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
254 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
255 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
256 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
257 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
258 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
259 },
260 // FSR attachment.
261 {
262 VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2, // VkStructureType sType;
263 nullptr, // const void* pNext;
264 0u, // VkAttachmentDescriptionFlags flags;
265 fsrFormat, // VkFormat format;
266 sampleCount, // VkSampleCountFlagBits samples;
267 VK_ATTACHMENT_LOAD_OP_LOAD, // VkAttachmentLoadOp loadOp;
268 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
269 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
270 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
271 VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR, // VkImageLayout initialLayout;
272 VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR, // VkImageLayout finalLayout;
273 },
274 };
275
276 const VkAttachmentReference2 colorAttRef = {
277 VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, // VkStructureType sType;
278 nullptr, // const void* pNext;
279 0u, // uint32_t attachment;
280 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout layout;
281 VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
282 };
283
284 const VkAttachmentReference2 fsrAttRef = {
285 VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, // VkStructureType sType;
286 nullptr, // const void* pNext;
287 1u, // uint32_t attachment;
288 VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR, // VkImageLayout layout;
289 VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
290 };
291
292 const VkFragmentShadingRateAttachmentInfoKHR fsrAttInfo = {
293 VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR, // VkStructureType sType;
294 nullptr, // const void* pNext;
295 &fsrAttRef, // const VkAttachmentReference2* pFragmentShadingRateAttachment;
296 makeExtent2D(vkExtent.width,
297 vkExtent.height), // VkExtent2D shadingRateAttachmentTexelSize;
298 };
299
300 const VkSubpassDescription2 subpassDescription{
301 VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2, // VkStructureType sType;
302 &fsrAttInfo, // const void* pNext;
303 0u, // VkSubpassDescriptionFlags flags;
304 bindPoint, // VkPipelineBindPoint pipelineBindPoint;
305 0u, // uint32_t viewMask;
306 0u, // uint32_t inputAttachmentCount;
307 nullptr, // const VkAttachmentReference2* pInputAttachments;
308 1u, // uint32_t colorAttachmentCount;
309 &colorAttRef, // const VkAttachmentReference2* pColorAttachments;
310 nullptr, // const VkAttachmentReference2* pResolveAttachments;
311 nullptr, // const VkAttachmentReference2* pDepthStencilAttachment;
312 0u, // uint32_t preserveAttachmentCount;
313 nullptr, // const uint32_t* pPreserveAttachments;
314 };
315
316 const VkRenderPassCreateInfo2 renderPassCreateInfo = {
317 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2, // VkStructureType sType;
318 nullptr, // const void* pNext;
319 0u, // VkRenderPassCreateFlags flags;
320 de::sizeU32(attachmentDescriptions), // uint32_t attachmentCount;
321 de::dataOrNull(attachmentDescriptions), // const VkAttachmentDescription2* pAttachments;
322 1u, // uint32_t subpassCount;
323 &subpassDescription, // const VkSubpassDescription2* pSubpasses;
324 0u, // uint32_t dependencyCount;
325 nullptr, // const VkSubpassDependency2* pDependencies;
326 0u, // uint32_t correlatedViewMaskCount;
327 nullptr, // const uint32_t* pCorrelatedViewMasks;
328 };
329
330 const auto renderPass = createRenderPass2(ctx.vkd, ctx.device, &renderPassCreateInfo);
331
332 const std::vector<VkImageView> attachmentViews{colorBuffer.getImageView(), fsrAttView.get()};
333 const auto framebuffer = makeFramebuffer(ctx.vkd, ctx.device, renderPass.get(), de::sizeU32(attachmentViews),
334 de::dataOrNull(attachmentViews), vkExtent.width, vkExtent.height);
335
336 const std::vector<VkViewport> viewports(1u, makeViewport(fbExtent));
337 const std::vector<VkRect2D> scissors(1u, makeRect2D(fbExtent));
338
339 // Use the rate according to the attachment.
340 const auto fragmentShadingRateStateCreateInfo = makeFragmentShadingRateStateCreateInfo(
341 1u, 1u, VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR, VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR);
342
343 const std::vector<tcu::Vec4> vertices{
344 tcu::Vec4(-1.0, -1.0f, 0.0f, 1.0f),
345 tcu::Vec4(-1.0, 1.0f, 0.0f, 1.0f),
346 tcu::Vec4(1.0, -1.0f, 0.0f, 1.0f),
347 tcu::Vec4(1.0, 1.0f, 0.0f, 1.0f),
348 };
349
350 const std::vector<tcu::Vec4> colors{
351 tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f),
352 tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
353 tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f),
354 tcu::Vec4(1.0f, 0.0f, 1.0f, 1.0f),
355 };
356
357 DE_ASSERT(vertices.size() == colors.size());
358
359 // We mix them reversing the color order for the first draw.
360 std::vector<PositionColor> vrsVertices;
361 std::vector<PositionColor> noVrsVertices;
362
363 vrsVertices.reserve(vertices.size());
364 noVrsVertices.reserve(vertices.size());
365
366 for (size_t i = 0; i < vertices.size(); ++i)
367 {
368 vrsVertices.push_back(PositionColor(vertices.at(i), colors.at(colors.size() - 1 - i)));
369 noVrsVertices.push_back(PositionColor(vertices.at(i), colors.at(i)));
370 }
371
372 const auto vertexBufferSize = static_cast<VkDeviceSize>(de::dataSize(vrsVertices));
373 const auto vertexBufferUsage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
374 const auto vertexBufferCreateInfo = makeBufferCreateInfo(vertexBufferSize, vertexBufferUsage);
375 const auto vertexBufferOffset = static_cast<VkDeviceSize>(0);
376
377 BufferWithMemory vrsVerticesBuffer(ctx.vkd, ctx.device, ctx.allocator, vertexBufferCreateInfo,
378 MemoryRequirement::HostVisible);
379 BufferWithMemory noVrsVerticesBuffer(ctx.vkd, ctx.device, ctx.allocator, vertexBufferCreateInfo,
380 MemoryRequirement::HostVisible);
381 auto &vrsVertAlloc = vrsVerticesBuffer.getAllocation();
382 auto &noVrsVertAlloc = noVrsVerticesBuffer.getAllocation();
383
384 deMemcpy(vrsVertAlloc.getHostPtr(), de::dataOrNull(vrsVertices), de::dataSize(vrsVertices));
385 deMemcpy(noVrsVertAlloc.getHostPtr(), de::dataOrNull(noVrsVertices), de::dataSize(noVrsVertices));
386 flushAlloc(ctx.vkd, ctx.device, vrsVertAlloc);
387 flushAlloc(ctx.vkd, ctx.device, noVrsVertAlloc);
388
389 const auto pipelineLayout = makePipelineLayout(ctx.vkd, ctx.device);
390
391 // Pipeline with and without VRS.
392 const auto pipelineVRS =
393 makeGraphicsPipeline(ctx.vkd, ctx.device, pipelineLayout.get(), vertModule.get(), VK_NULL_HANDLE,
394 VK_NULL_HANDLE, VK_NULL_HANDLE, fragModule.get(), renderPass.get(), viewports, scissors,
395 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 0u, 0u, getDefaultVertexInputStateCreateInfo(),
396 nullptr, nullptr, nullptr, nullptr, nullptr, &fragmentShadingRateStateCreateInfo);
397
398 const auto pipelineNoVRS =
399 makeGraphicsPipeline(ctx.vkd, ctx.device, pipelineLayout.get(), vertModule.get(), VK_NULL_HANDLE,
400 VK_NULL_HANDLE, VK_NULL_HANDLE, fragModule.get(), renderPass.get(), viewports, scissors,
401 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 0u, 0u, getDefaultVertexInputStateCreateInfo());
402
403 CommandPoolWithBuffer cmd(ctx.vkd, ctx.device, ctx.qfIndex);
404 const auto cmdBuffer = cmd.cmdBuffer.get();
405
406 #if 0
407 const int gl_ShadingRateFlag2VerticalPixelsEXT = 1;
408 const int gl_ShadingRateFlag4VerticalPixelsEXT = 2;
409 const int gl_ShadingRateFlag2HorizontalPixelsEXT = 4;
410 const int gl_ShadingRateFlag4HorizontalPixelsEXT = 8;
411 #endif
412 using ClearValueVec = std::vector<VkClearValue>;
413 const uint32_t clearAttRate =
414 5u; // 2x2: (gl_ShadingRateFlag2HorizontalPixelsEXT | gl_ShadingRateFlag2VerticalPixelsEXT)
415 const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 0.0f);
416 const ClearValueVec clearValues{
417 makeClearValueColor(clearColor),
418 };
419 const auto colorCompThreshold = 0.005f; // between 1/255 and 2/255.
420 const tcu::Vec4 colorThreshold(colorCompThreshold, colorCompThreshold, colorCompThreshold, colorCompThreshold);
421 const auto vertexCount = de::sizeU32(vertices);
422
423 tcu::TextureFormat fsrTextureFormat = mapVkFormat(fsrFormat);
424 size_t fsrFillBufferSize = fsrExtent.width * fsrExtent.height * getNumUsedChannels(fsrTextureFormat.order) *
425 getChannelSize(fsrTextureFormat.type);
426 BufferWithMemory fsrFillBuffer(ctx.vkd, ctx.device, ctx.allocator,
427 makeBufferCreateInfo(fsrFillBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT),
428 MemoryRequirement::HostVisible);
429 auto fillPtr = (uint8_t *)fsrFillBuffer.getAllocation().getHostPtr();
430 memset(fillPtr, clearAttRate, (size_t)fsrFillBufferSize);
431 flushAlloc(ctx.vkd, ctx.device, fsrFillBuffer.getAllocation());
432
433 const struct
434 {
435 VkBuffer vertexBuffer;
436 VkPipeline pipeline;
437 } iterations[] = {
438 {vrsVerticesBuffer.get(), pipelineVRS.get()},
439 {noVrsVerticesBuffer.get(), pipelineNoVRS.get()},
440 };
441
442 beginCommandBuffer(ctx.vkd, cmdBuffer);
443 {
444 // Initialize the FSR attachment.
445 const auto preTransferBarrier =
446 makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL,
447 fsrAttachment.get(), colorSRR);
448 cmdPipelineImageMemoryBarrier(ctx.vkd, cmdBuffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
449 VK_PIPELINE_STAGE_TRANSFER_BIT, &preTransferBarrier);
450 const auto copyRegion = makeBufferImageCopy(fsrExtent, colorSRL);
451 ctx.vkd.cmdCopyBufferToImage(cmdBuffer, fsrFillBuffer.get(), fsrAttachment.get(), VK_IMAGE_LAYOUT_GENERAL, 1u,
452 ©Region);
453 const auto postTransferBarrier = makeImageMemoryBarrier(
454 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR,
455 VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR, fsrAttachment.get(),
456 colorSRR);
457 cmdPipelineImageMemoryBarrier(ctx.vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT,
458 VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR, &postTransferBarrier);
459 }
460 {
461 // Render pass.
462 beginRenderPass(ctx.vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0u),
463 de::sizeU32(clearValues), de::dataOrNull(clearValues));
464 for (const auto &iteration : iterations)
465 {
466 ctx.vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &iteration.vertexBuffer, &vertexBufferOffset);
467 ctx.vkd.cmdBindPipeline(cmdBuffer, bindPoint, iteration.pipeline);
468 ctx.vkd.cmdDraw(cmdBuffer, vertexCount, 1u, 0u, 0u);
469 }
470 endRenderPass(ctx.vkd, cmdBuffer);
471 }
472 {
473 // Copy image to verification buffer after rendering.
474 const auto preTransferBarrier = makeImageMemoryBarrier(
475 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
476 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorBuffer.getImage(), colorSRR);
477 cmdPipelineImageMemoryBarrier(ctx.vkd, cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
478 VK_PIPELINE_STAGE_TRANSFER_BIT, &preTransferBarrier);
479 const auto copyRegion = makeBufferImageCopy(vkExtent, colorSRL);
480 ctx.vkd.cmdCopyImageToBuffer(cmdBuffer, colorBuffer.getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
481 colorBuffer.getBuffer(), 1u, ©Region);
482 const auto preHostBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
483 cmdPipelineMemoryBarrier(ctx.vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT,
484 &preHostBarrier);
485 }
486 endCommandBuffer(ctx.vkd, cmdBuffer);
487 submitCommandsAndWait(ctx.vkd, ctx.device, ctx.queue, cmdBuffer);
488 invalidateAlloc(ctx.vkd, ctx.device, colorBuffer.getBufferAllocation());
489
490 // Create expected reference image.
491 const auto tcuFormat = mapVkFormat(colorFormat);
492 tcu::TextureLevel referenceLevel(tcuFormat, fbExtent.x(), fbExtent.y());
493 tcu::PixelBufferAccess referenceAccess = referenceLevel.getAccess();
494
495 const auto &xSize = fbExtent.x();
496 const auto &ySize = fbExtent.y();
497 const auto xSizeF = static_cast<float>(xSize);
498 const auto ySizeF = static_cast<float>(ySize);
499
500 // This must match the vertex+color combination for the second draw.
501 // Red goes from 0 to 1 on the X axis, Blue goes from 0 to 1 on the Y axis.
502 for (int y = 0; y < fbExtent.y(); ++y)
503 for (int x = 0; x < fbExtent.x(); ++x)
504 {
505 const float red = (static_cast<float>(y) + 0.5f) / ySizeF;
506 const float blue = (static_cast<float>(x) + 0.5f) / xSizeF;
507 const tcu::Vec4 refColor(red, 0.0f, blue, 1.0f);
508
509 referenceAccess.setPixel(refColor, x, y);
510 }
511
512 auto &log = context.getTestContext().getLog();
513 const tcu::ConstPixelBufferAccess resultAccess(tcuFormat, fbExtent, colorBuffer.getBufferAllocation().getHostPtr());
514
515 if (!tcu::floatThresholdCompare(log, "Result", "", referenceAccess, resultAccess, colorThreshold,
516 tcu::COMPARE_LOG_ON_ERROR))
517 return tcu::TestStatus::fail("Unexpected color buffer contents -- check log for details");
518 return tcu::TestStatus::pass("Pass");
519 }
520
testNoFrag(Context & context)521 tcu::TestStatus testNoFrag(Context &context)
522 {
523 const auto ctx = context.getContextCommonData();
524 const auto colorFormat = VK_FORMAT_R8G8B8A8_UNORM;
525 const auto colorUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
526 const auto colorSRR = makeDefaultImageSubresourceRange();
527 const auto colorSRL = makeDefaultImageSubresourceLayers();
528 const auto depthFormat = VK_FORMAT_D16_UNORM;
529 const auto depthUsage = (VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
530 const auto depthSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 1u, 0u, 1u);
531 const auto depthSRL = makeImageSubresourceLayers(VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 0u, 1u);
532 const auto bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
533 const auto vkExtent = makeExtent3D(8u, 1u, 1u);
534 const tcu::IVec3 fbExtent(static_cast<int>(vkExtent.width), static_cast<int>(vkExtent.height),
535 static_cast<int>(vkExtent.depth));
536 const auto imageType = VK_IMAGE_TYPE_2D;
537 const tcu::IVec2 tileSize(2, 2);
538
539 vk::ImageWithBuffer colorBuffer(ctx.vkd, ctx.device, ctx.allocator, vkExtent, colorFormat, colorUsage, imageType,
540 colorSRR);
541 vk::ImageWithBuffer depthBuffer(ctx.vkd, ctx.device, ctx.allocator, vkExtent, depthFormat, depthUsage, imageType,
542 depthSRR);
543
544 const auto vertModule = createShaderModule(ctx.vkd, ctx.device, context.getBinaryCollection().get("vert"));
545 const auto renderPass = makeRenderPass(ctx.vkd, ctx.device, colorFormat, depthFormat);
546
547 const std::vector<VkImageView> attachmentViews{colorBuffer.getImageView(), depthBuffer.getImageView()};
548 const auto framebuffer = makeFramebuffer(ctx.vkd, ctx.device, renderPass.get(), de::sizeU32(attachmentViews),
549 de::dataOrNull(attachmentViews), vkExtent.width, vkExtent.height);
550
551 const std::vector<VkViewport> viewports(1u, makeViewport(fbExtent));
552 const std::vector<VkRect2D> scissors(1u, makeRect2D(fbExtent));
553
554 // Use the rate from the pipeline.
555 const auto fragmentShadingRateStateCreateInfo = makeFragmentShadingRateStateCreateInfo(
556 static_cast<uint32_t>(tileSize.x()), static_cast<uint32_t>(tileSize.y()), // This has mandatory support.
557 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR, VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR);
558
559 const std::vector<PositionColor> vertices{
560 // Colors (second column) are irrelevant due to the lack of a frag shader.
561 // In the first column we increase depth as we advance from left to right.
562 {tcu::Vec4(-1.0, -1.0f, 0.0f, 1.0f), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)},
563 {tcu::Vec4(-1.0, 1.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)},
564 {tcu::Vec4(1.0, -1.0f, 1.0f, 1.0f), tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f)},
565 {tcu::Vec4(1.0, 1.0f, 1.0f, 1.0f), tcu::Vec4(1.0f, 0.0f, 1.0f, 1.0f)},
566 };
567
568 const auto vertexBufferSize = static_cast<VkDeviceSize>(de::dataSize(vertices));
569 const auto vertexBufferUsage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
570 const auto vertexBufferCreateInfo = makeBufferCreateInfo(vertexBufferSize, vertexBufferUsage);
571 const auto vertexBufferOffset = static_cast<VkDeviceSize>(0);
572 BufferWithMemory vertexBuffer(ctx.vkd, ctx.device, ctx.allocator, vertexBufferCreateInfo,
573 MemoryRequirement::HostVisible);
574 auto &vertexBufferAlloc = vertexBuffer.getAllocation();
575
576 deMemcpy(vertexBufferAlloc.getHostPtr(), de::dataOrNull(vertices), de::dataSize(vertices));
577 flushAlloc(ctx.vkd, ctx.device, vertexBufferAlloc);
578
579 const auto pipelineLayout = makePipelineLayout(ctx.vkd, ctx.device);
580
581 const VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo = {
582 VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
583 nullptr, // const void* pNext;
584 0u, // VkPipelineDepthStencilStateCreateFlags flags;
585 VK_TRUE, // VkBool32 depthTestEnable;
586 VK_TRUE, // VkBool32 depthWriteEnable;
587 VK_COMPARE_OP_ALWAYS, // VkCompareOp depthCompareOp;
588 VK_FALSE, // VkBool32 depthBoundsTestEnable;
589 VK_FALSE, // VkBool32 stencilTestEnable;
590 {}, // VkStencilOpState front;
591 {}, // VkStencilOpState back;
592 0.0f, // float minDepthBounds;
593 1.0f, // float maxDepthBounds;
594 };
595
596 // We need to force-enable rasterization at this step, otherwise the helper will disable it due to missing frag shader.
597 const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = {
598 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
599 nullptr, // const void* pNext;
600 0u, // VkPipelineRasterizationStateCreateFlags flags;
601 VK_FALSE, // VkBool32 depthClampEnable;
602 VK_FALSE, // VkBool32 rasterizerDiscardEnable;
603 VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode;
604 VK_CULL_MODE_NONE, // VkCullModeFlags cullMode;
605 VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace;
606 VK_FALSE, // VkBool32 depthBiasEnable;
607 0.0f, // float depthBiasConstantFactor;
608 0.0f, // float depthBiasClamp;
609 0.0f, // float depthBiasSlopeFactor;
610 1.0f, // float lineWidth;
611 };
612
613 // Pipeline.
614 const auto pipeline = makeGraphicsPipeline(
615 ctx.vkd, ctx.device, pipelineLayout.get(), vertModule.get(), VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE,
616 VK_NULL_HANDLE, renderPass.get(), viewports, scissors, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 0u, 0u,
617 getDefaultVertexInputStateCreateInfo(), &rasterizationStateCreateInfo, nullptr, &depthStencilStateCreateInfo,
618 nullptr, nullptr, &fragmentShadingRateStateCreateInfo);
619
620 CommandPoolWithBuffer cmd(ctx.vkd, ctx.device, ctx.qfIndex);
621 const auto cmdBuffer = cmd.cmdBuffer.get();
622
623 using ClearValueVec = std::vector<VkClearValue>;
624 const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 0.0f);
625 const float clearDepth = 1.0f;
626 const ClearValueVec clearValues{
627 makeClearValueColor(clearColor),
628 makeClearValueDepthStencil(clearDepth, 0u),
629 };
630 const auto colorCompThreshold = 0.0f; // Expect exact results.
631 const tcu::Vec4 colorThreshold(colorCompThreshold, colorCompThreshold, colorCompThreshold, colorCompThreshold);
632 const float depthThreshold = 0.000025f; // Between 1/65535 and 2/65535.
633 const auto vertexCount = de::sizeU32(vertices);
634
635 beginCommandBuffer(ctx.vkd, cmdBuffer);
636 {
637 // Render pass.
638 beginRenderPass(ctx.vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0u),
639 de::sizeU32(clearValues), de::dataOrNull(clearValues));
640 ctx.vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
641 ctx.vkd.cmdBindPipeline(cmdBuffer, bindPoint, pipeline.get());
642 ctx.vkd.cmdDraw(cmdBuffer, vertexCount, 1u, 0u, 0u);
643 endRenderPass(ctx.vkd, cmdBuffer);
644 }
645 {
646 // Copy images to verification buffers after rendering.
647 const std::vector<VkImageMemoryBarrier> preTransferBarriers = {
648 makeImageMemoryBarrier(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
649 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
650 colorBuffer.getImage(), colorSRR),
651
652 makeImageMemoryBarrier(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
653 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
654 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, depthBuffer.getImage(), depthSRR),
655 };
656 const auto preTransferStages =
657 (VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
658 VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
659 cmdPipelineImageMemoryBarrier(ctx.vkd, cmdBuffer, preTransferStages, VK_PIPELINE_STAGE_TRANSFER_BIT,
660 de::dataOrNull(preTransferBarriers), preTransferBarriers.size());
661
662 const auto copyColorRegion = makeBufferImageCopy(vkExtent, colorSRL);
663 const auto copyDepthRegion = makeBufferImageCopy(vkExtent, depthSRL);
664 ctx.vkd.cmdCopyImageToBuffer(cmdBuffer, colorBuffer.getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
665 colorBuffer.getBuffer(), 1u, ©ColorRegion);
666 ctx.vkd.cmdCopyImageToBuffer(cmdBuffer, depthBuffer.getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
667 depthBuffer.getBuffer(), 1u, ©DepthRegion);
668
669 const auto preHostBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
670 cmdPipelineMemoryBarrier(ctx.vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT,
671 &preHostBarrier);
672 }
673 endCommandBuffer(ctx.vkd, cmdBuffer);
674 submitCommandsAndWait(ctx.vkd, ctx.device, ctx.queue, cmdBuffer);
675 invalidateAlloc(ctx.vkd, ctx.device, colorBuffer.getBufferAllocation());
676 invalidateAlloc(ctx.vkd, ctx.device, depthBuffer.getBufferAllocation());
677
678 // Check results:
679 // - Color image shouldn't have been touched.
680 // - Depth buffer should have values in pairs of 2, within the accepted range.
681 const auto colorTcuFormat = mapVkFormat(colorFormat);
682 const auto depthTcuFormat = mapVkFormat(depthFormat);
683 const tcu::ConstPixelBufferAccess colorResultAccess(colorTcuFormat, fbExtent,
684 colorBuffer.getBufferAllocation().getHostPtr());
685 const tcu::ConstPixelBufferAccess depthResultAccess(depthTcuFormat, fbExtent,
686 depthBuffer.getBufferAllocation().getHostPtr());
687
688 auto &log = context.getTestContext().getLog();
689 if (!tcu::floatThresholdCompare(log, "ColorResult", "", clearColor, colorResultAccess, colorThreshold,
690 tcu::COMPARE_LOG_ON_ERROR))
691 return tcu::TestStatus::fail(
692 "Unexpected color buffer contents (expected transparent black) -- check log for details");
693
694 // Note fragment shading rate does not affect the depth buffer, only frag shader invocations.
695 // When verifying the depth buffer, we'll generate the reference values normally.
696 tcu::TextureLevel refDepthLevel(depthTcuFormat, fbExtent.x(), fbExtent.y(), fbExtent.z());
697 tcu::PixelBufferAccess refDepthAccess = refDepthLevel.getAccess();
698 const float fWidth = static_cast<float>(fbExtent.x());
699
700 for (int y = 0; y < fbExtent.y(); ++y)
701 for (int x = 0; x < fbExtent.x(); ++x)
702 {
703 // This needs to match vertex depths.
704 const float depth = (static_cast<float>(x) + 0.5f) / fWidth;
705 refDepthAccess.setPixDepth(depth, x, y);
706 }
707
708 if (!tcu::dsThresholdCompare(log, "DepthResult", "", refDepthAccess, depthResultAccess, depthThreshold,
709 tcu::COMPARE_LOG_ON_ERROR))
710 return tcu::TestStatus::fail("Unexpected depth buffer contents -- check log for details");
711
712 return tcu::TestStatus::pass("Pass");
713 }
714
715 } // namespace
716
createFragmentShadingRateMiscTests(tcu::TestCaseGroup * group)717 void createFragmentShadingRateMiscTests(tcu::TestCaseGroup *group)
718 {
719 {
720 const char *testName = "enable_disable_attachment";
721 // Test drawing with VRS enabled by an attachment and then disabled
722 addFunctionCaseWithPrograms(group, testName, checkEnableDisableSupport, initEnableDisableShaders,
723 testEnableDisable);
724 }
725 {
726 const char *testName = "no_frag_shader";
727 // Test drawing with VRS enabled and no frag shader
728 addFunctionCaseWithPrograms(group, testName, checkNoFragSupport, initNoFragShaders, testNoFrag);
729 }
730 }
731
732 } // namespace FragmentShadingRate
733 } // namespace vkt
734