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                                      &copyRegion);
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, &copyRegion);
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, &copyColorRegion);
666         ctx.vkd.cmdCopyImageToBuffer(cmdBuffer, depthBuffer.getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
667                                      depthBuffer.getBuffer(), 1u, &copyDepthRegion);
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