• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 Extended dynamic state misc tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktPipelineExtendedDynamicStateMiscTests.hpp"
26 #include "tcuTextureUtil.hpp"
27 #include "vkBarrierUtil.hpp"
28 #include "vktTestCase.hpp"
29 #include "vktTestCaseUtil.hpp"
30 #include "vkBuilderUtil.hpp"
31 #include "vkCmdUtil.hpp"
32 #include "vkImageUtil.hpp"
33 #include "vkObjUtil.hpp"
34 
35 #include "tcuImageCompare.hpp"
36 
37 #include "deUniquePtr.hpp"
38 
39 #include <sstream>
40 #include <vector>
41 #include <memory>
42 #include <utility>
43 
44 namespace vkt
45 {
46 namespace pipeline
47 {
48 
49 namespace
50 {
51 
52 using namespace vk;
53 
54 constexpr uint32_t kVertexCount = 4u;
55 
checkDynamicRasterizationSamplesSupport(Context & context)56 void checkDynamicRasterizationSamplesSupport(Context &context)
57 {
58 #ifndef CTS_USES_VULKANSC
59     if (!context.getExtendedDynamicState3FeaturesEXT().extendedDynamicState3RasterizationSamples)
60         TCU_THROW(NotSupportedError, "extendedDynamicState3RasterizationSamples not supported");
61 #else
62     DE_UNREF(context);
63     TCU_THROW(NotSupportedError, "extendedDynamicState3RasterizationSamples not supported");
64 #endif // CTS_USES_VULKANSC
65 }
66 
sampleShadingWithDynamicSampleCountSupport(Context & context,PipelineConstructionType pipelineConstructionType)67 void sampleShadingWithDynamicSampleCountSupport(Context &context, PipelineConstructionType pipelineConstructionType)
68 {
69     checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
70                                           pipelineConstructionType);
71     checkDynamicRasterizationSamplesSupport(context);
72     context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_FRAGMENT_STORES_AND_ATOMICS);
73     context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SAMPLE_RATE_SHADING);
74 }
75 
initFullScreenQuadVertexProgram(vk::SourceCollections & programCollection,const char * name)76 void initFullScreenQuadVertexProgram(vk::SourceCollections &programCollection, const char *name)
77 {
78     std::ostringstream vert;
79     vert << "#version 460\n"
80          << "vec2 positions[" << kVertexCount << "] = vec2[](\n"
81          << "    vec2(-1.0, -1.0),\n"
82          << "    vec2(-1.0,  1.0),\n"
83          << "    vec2( 1.0, -1.0),\n"
84          << "    vec2( 1.0,  1.0)\n"
85          << ");\n"
86          << "void main (void) {\n"
87          << "    gl_Position = vec4(positions[gl_VertexIndex % " << kVertexCount << "], 0.0, 1.0);\n"
88          << "}\n";
89     programCollection.glslSources.add(name) << glu::VertexSource(vert.str());
90 }
91 
initBlueAndAtomicCounterFragmentProgram(vk::SourceCollections & programCollection,const char * name)92 void initBlueAndAtomicCounterFragmentProgram(vk::SourceCollections &programCollection, const char *name)
93 {
94     std::ostringstream frag;
95     frag << "#version 460\n"
96          << "layout (location=0) out vec4 outColor;\n"
97          << "layout (set=0, binding=0) buffer InvocationCounterBlock { uint invocations; } counterBuffer;\n"
98          << "void main (void) {\n"
99          << "    uint sampleId = gl_SampleID;\n" // Enable sample shading for shader objects by reading gl_SampleID
100          << "    atomicAdd(counterBuffer.invocations, 1u);\n"
101          << "    outColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
102          << "}\n";
103     programCollection.glslSources.add(name) << glu::FragmentSource(frag.str());
104 }
105 
sampleShadingWithDynamicSampleCountPrograms(vk::SourceCollections & programCollection,PipelineConstructionType)106 void sampleShadingWithDynamicSampleCountPrograms(vk::SourceCollections &programCollection, PipelineConstructionType)
107 {
108     initFullScreenQuadVertexProgram(programCollection, "vert");
109     initBlueAndAtomicCounterFragmentProgram(programCollection, "frag");
110 }
111 
verifyValueInRange(uint32_t value,uint32_t minValue,uint32_t maxValue,const char * valueDesc)112 void verifyValueInRange(uint32_t value, uint32_t minValue, uint32_t maxValue, const char *valueDesc)
113 {
114     if (value < minValue || value > maxValue)
115     {
116         std::ostringstream msg;
117         msg << "Unexpected value found for " << valueDesc << ": " << value << " not in range [" << minValue << ", "
118             << maxValue << "]";
119         TCU_FAIL(msg.str());
120     }
121 }
122 /*
123  * begin cmdbuf
124  * bind pipeline with sample shading disabled
125  * call vkCmdSetRasterizationSamplesEXT(samples > 1)
126  * draw
127  * bind pipeline with sample shading enabled
128  * draw
129  * sample shading should work for both draws with the expected number of samples
130  *
131  * Each draw will use one half of the framebuffer, controlled by the viewport and scissor.
132  */
sampleShadingWithDynamicSampleCount(Context & context,PipelineConstructionType constructionType)133 tcu::TestStatus sampleShadingWithDynamicSampleCount(Context &context, PipelineConstructionType constructionType)
134 {
135     const auto ctx = context.getContextCommonData();
136     const tcu::IVec3 fbExtent(2, 2, 1);
137     const auto vkExtent           = makeExtent3D(fbExtent);
138     const auto colorFormat        = VK_FORMAT_R8G8B8A8_UNORM;
139     const auto colorUsage         = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
140     const auto descriptorType     = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
141     const auto descriptorStages   = VK_SHADER_STAGE_FRAGMENT_BIT;
142     const auto kNumDraws          = 2u;
143     const auto bindPoint          = VK_PIPELINE_BIND_POINT_GRAPHICS;
144     const auto colorSRR           = makeDefaultImageSubresourceRange();
145     const auto kMultiSampleCount  = VK_SAMPLE_COUNT_4_BIT;
146     const auto kSingleSampleCount = VK_SAMPLE_COUNT_1_BIT;
147     const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 0.0f);
148     const tcu::Vec4 geomColor(0.0f, 0.0f, 1.0f, 1.0f); // Must match frag shader.
149     const auto topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
150 
151     // Color buffers.
152     ImageWithBuffer colorBuffer(ctx.vkd, ctx.device, ctx.allocator, vkExtent, colorFormat, colorUsage, VK_IMAGE_TYPE_2D,
153                                 colorSRR, 1u, kMultiSampleCount);
154     ImageWithBuffer resolveBuffer(ctx.vkd, ctx.device, ctx.allocator, vkExtent, colorFormat, colorUsage,
155                                   VK_IMAGE_TYPE_2D, colorSRR, 1u, kSingleSampleCount);
156 
157     // Counter buffers.
158     using BufferPtr = std::unique_ptr<BufferWithMemory>;
159     using BufferVec = std::vector<BufferPtr>;
160 
161     const auto counterBufferSize = static_cast<VkDeviceSize>(sizeof(uint32_t));
162     const auto counterBufferInfo = makeBufferCreateInfo(counterBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
163 
164     BufferVec counterBuffers;
165 
166     for (uint32_t drawIdx = 0u; drawIdx < kNumDraws; ++drawIdx)
167     {
168         BufferPtr counterBuffer(new BufferWithMemory(ctx.vkd, ctx.device, ctx.allocator, counterBufferInfo,
169                                                      MemoryRequirement::HostVisible));
170         auto &counterBufferAlloc = counterBuffer->getAllocation();
171         void *counterBufferPtr   = counterBufferAlloc.getHostPtr();
172 
173         deMemset(counterBufferPtr, 0, static_cast<size_t>(counterBufferSize));
174         flushAlloc(ctx.vkd, ctx.device, counterBufferAlloc);
175 
176         counterBuffers.emplace_back(std::move(counterBuffer));
177     }
178 
179     // Descriptor set layout, pool and set.
180     DescriptorSetLayoutBuilder setLayoutbuilder;
181     setLayoutbuilder.addSingleBinding(descriptorType, descriptorStages);
182     const auto setLayout = setLayoutbuilder.build(ctx.vkd, ctx.device);
183 
184     DescriptorPoolBuilder poolBuilder;
185     poolBuilder.addType(descriptorType, kNumDraws);
186     const auto descriptorPool =
187         poolBuilder.build(ctx.vkd, ctx.device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, kNumDraws);
188 
189     using DescriptorSetVec = std::vector<Move<VkDescriptorSet>>;
190     DescriptorSetVec descriptorSets;
191 
192     for (uint32_t drawIdx = 0u; drawIdx < kNumDraws; ++drawIdx)
193     {
194         descriptorSets.emplace_back(makeDescriptorSet(ctx.vkd, ctx.device, *descriptorPool, *setLayout));
195 
196         DescriptorSetUpdateBuilder updateBuilder;
197         const auto counterBufferDescriptorInfo =
198             makeDescriptorBufferInfo(counterBuffers.at(drawIdx)->get(), 0ull, counterBufferSize);
199         updateBuilder.writeSingle(*descriptorSets.back(), DescriptorSetUpdateBuilder::Location::binding(0u),
200                                   descriptorType, &counterBufferDescriptorInfo);
201         updateBuilder.update(ctx.vkd, ctx.device);
202     }
203 
204     // Render pass and framebuffer.
205     const std::vector<VkAttachmentDescription> attachmentDescs{
206         // Multisample attachment.
207         makeAttachmentDescription(0u, colorFormat, kMultiSampleCount, VK_ATTACHMENT_LOAD_OP_CLEAR,
208                                   VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_ATTACHMENT_LOAD_OP_DONT_CARE,
209                                   VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_UNDEFINED,
210                                   VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL),
211 
212         // Resolve attachment.
213         makeAttachmentDescription(0u, colorFormat, kSingleSampleCount, VK_ATTACHMENT_LOAD_OP_DONT_CARE,
214                                   VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE,
215                                   VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_UNDEFINED,
216                                   VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL),
217     };
218 
219     const auto colorAttRef   = makeAttachmentReference(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
220     const auto resolveAttRef = makeAttachmentReference(1u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
221     const auto subpassDescription =
222         makeSubpassDescription(0u, bindPoint, 0u, nullptr, 1u, &colorAttRef, &resolveAttRef, nullptr, 0u, nullptr);
223 
224     const VkRenderPassCreateInfo renderPassCreateInfo = {
225         VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
226         nullptr,                                   // const void* pNext;
227         0u,                                        // VkRenderPassCreateFlags flags;
228         de::sizeU32(attachmentDescs),              // uint32_t attachmentCount;
229         de::dataOrNull(attachmentDescs),           // const VkAttachmentDescription* pAttachments;
230         1u,                                        // uint32_t subpassCount;
231         &subpassDescription,                       // const VkSubpassDescription* pSubpasses;
232         0u,                                        // uint32_t dependencyCount;
233         nullptr,                                   // const VkSubpassDependency* pDependencies;
234     };
235     auto renderPass = RenderPassWrapper(constructionType, ctx.vkd, ctx.device, &renderPassCreateInfo);
236 
237     const std::vector<VkImage> images{colorBuffer.getImage(), resolveBuffer.getImage()};
238     const std::vector<VkImageView> imageViews{colorBuffer.getImageView(), resolveBuffer.getImageView()};
239     renderPass.createFramebuffer(ctx.vkd, ctx.device, de::sizeU32(imageViews), de::dataOrNull(images),
240                                  de::dataOrNull(imageViews), vkExtent.width, vkExtent.height);
241 
242     // Pipelines.
243     const auto &binaries   = context.getBinaryCollection();
244     const auto &vertModule = ShaderWrapper(ctx.vkd, ctx.device, binaries.get("vert"));
245     const auto &fragModule = ShaderWrapper(ctx.vkd, ctx.device, binaries.get("frag"));
246 
247     const std::vector<VkDynamicState> dynamicStates{
248 #ifndef CTS_USES_VULKANSC
249         VK_DYNAMIC_STATE_RASTERIZATION_SAMPLES_EXT,
250 #endif // CTS_USES_VULKANSC
251         VK_DYNAMIC_STATE_SCISSOR,
252         VK_DYNAMIC_STATE_VIEWPORT,
253     };
254 
255     const VkPipelineDynamicStateCreateInfo dynamicStateInfo = {
256         VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
257         nullptr,                                              // const void* pNext;
258         0u,                                                   // VkPipelineDynamicStateCreateFlags flags;
259         de::sizeU32(dynamicStates),                           // uint32_t dynamicStateCount;
260         de::dataOrNull(dynamicStates),                        // const VkDynamicState* pDynamicStates;
261     };
262 
263     const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = initVulkanStructureConst();
264 
265     VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo = {
266         VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
267         nullptr,                                                  // const void* pNext;
268         0u,                                                       // VkPipelineMultisampleStateCreateFlags flags;
269         VK_SAMPLE_COUNT_64_BIT,                                   // VkSampleCountFlagBits rasterizationSamples;
270         VK_FALSE,                                                 // VkBool32 sampleShadingEnable;
271         1.0f,                                                     // float minSampleShading;
272         nullptr,                                                  // const VkSampleMask* pSampleMask;
273         VK_FALSE,                                                 // VkBool32 alphaToCoverageEnable;
274         VK_FALSE,                                                 // VkBool32 alphaToOneEnable;
275     };
276 
277     const std::vector<VkViewport> staticViewports(1u, makeViewport(0u, 0u));
278     const std::vector<VkRect2D> staticScissors(1u, makeRect2D(0u, 0u));
279     const PipelineLayoutWrapper pipelineLayout(constructionType, ctx.vkd, ctx.device, *setLayout);
280     const auto renderArea     = makeRect2D(fbExtent);
281     const int halfWidth       = fbExtent.x() / 2;
282     const uint32_t halfWidthU = static_cast<uint32_t>(halfWidth);
283     const float halfWidthF    = static_cast<float>(halfWidth);
284     const float heightF       = static_cast<float>(vkExtent.height);
285     const std::vector<VkRect2D> dynamicScissors{makeRect2D(0, 0, halfWidthU, vkExtent.height),
286                                                 makeRect2D(halfWidth, 0, halfWidthU, vkExtent.height)};
287     const std::vector<VkViewport> dynamicViewports{
288         makeViewport(0.0f, 0.0f, halfWidthF, heightF, 0.0f, 1.0f),
289         makeViewport(halfWidthF, 0.0f, halfWidthF, heightF, 0.0f, 1.0f),
290     };
291 
292     using WrapperPtr = std::unique_ptr<GraphicsPipelineWrapper>;
293     using WrapperVec = std::vector<WrapperPtr>;
294 
295     WrapperVec wrappers;
296 
297     for (const auto sampleShadingEnable : {false, true})
298     {
299         multisampleStateCreateInfo.sampleShadingEnable = sampleShadingEnable;
300 
301         WrapperPtr pipelineWrapper(new GraphicsPipelineWrapper(ctx.vki, ctx.vkd, ctx.physicalDevice, ctx.device,
302                                                                context.getDeviceExtensions(), constructionType));
303         pipelineWrapper->setDefaultTopology(topology)
304             .setDefaultRasterizationState()
305             .setDefaultColorBlendState()
306             .setDynamicState(&dynamicStateInfo)
307             .setupVertexInputState(&vertexInputStateCreateInfo)
308             .setupPreRasterizationShaderState(staticViewports, staticScissors, pipelineLayout, *renderPass, 0u,
309                                               vertModule)
310             .setupFragmentShaderState(pipelineLayout, *renderPass, 0u, fragModule, nullptr, &multisampleStateCreateInfo)
311             .setupFragmentOutputState(*renderPass, 0u, nullptr, &multisampleStateCreateInfo)
312             .setMonolithicPipelineLayout(pipelineLayout)
313             .buildPipeline();
314 
315         wrappers.emplace_back(std::move(pipelineWrapper));
316     }
317 
318     CommandPoolWithBuffer cmd(ctx.vkd, ctx.device, ctx.qfIndex);
319     const auto cmdBuffer = cmd.cmdBuffer.get();
320 
321     beginCommandBuffer(ctx.vkd, cmdBuffer);
322     renderPass.begin(ctx.vkd, cmdBuffer, renderArea, clearColor);
323     for (uint32_t drawIdx = 0u; drawIdx < kNumDraws; ++drawIdx)
324     {
325         wrappers.at(drawIdx)->bind(cmdBuffer);
326         if (drawIdx == 0u)
327         {
328 #ifndef CTS_USES_VULKANSC
329             ctx.vkd.cmdSetRasterizationSamplesEXT(cmdBuffer, kMultiSampleCount);
330 #else
331             DE_ASSERT(false);
332 #endif // CTS_USES_VULKANSC
333         }
334 #ifndef CTS_USES_VULKANSC
335         if (isConstructionTypeShaderObject(constructionType))
336         {
337             ctx.vkd.cmdSetScissorWithCount(cmdBuffer, 1u, &dynamicScissors.at(drawIdx));
338             ctx.vkd.cmdSetViewportWithCount(cmdBuffer, 1u, &dynamicViewports.at(drawIdx));
339         }
340         else
341 #endif // CTS_USES_VULKANSC
342         {
343             ctx.vkd.cmdSetScissor(cmdBuffer, 0u, 1u, &dynamicScissors.at(drawIdx));
344             ctx.vkd.cmdSetViewport(cmdBuffer, 0u, 1u, &dynamicViewports.at(drawIdx));
345         }
346         ctx.vkd.cmdBindDescriptorSets(cmdBuffer, bindPoint, *pipelineLayout, 0u, 1u, &descriptorSets.at(drawIdx).get(),
347                                       0u, nullptr);
348         ctx.vkd.cmdDraw(cmdBuffer, kVertexCount, 1u, 0u, 0u);
349     }
350     renderPass.end(ctx.vkd, cmdBuffer);
351     copyImageToBuffer(ctx.vkd, cmdBuffer, resolveBuffer.getImage(), resolveBuffer.getBuffer(), fbExtent.swizzle(0, 1),
352                       VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1u,
353                       VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_ASPECT_COLOR_BIT,
354                       VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
355     endCommandBuffer(ctx.vkd, cmdBuffer);
356     submitCommandsAndWait(ctx.vkd, ctx.device, ctx.queue, cmdBuffer);
357 
358     // Verify resolve buffer and counter buffers.
359     auto &log = context.getTestContext().getLog();
360     {
361         const tcu::Vec4 threshold(0.0f, 0.0f, 0.0f, 0.0f); // Expect exact results.
362         const auto tcuFormat           = mapVkFormat(colorFormat);
363         const auto &resolveBufferAlloc = resolveBuffer.getBufferAllocation();
364         const auto resolveBufferData   = resolveBufferAlloc.getHostPtr();
365 
366         invalidateAlloc(ctx.vkd, ctx.device, resolveBufferAlloc);
367         const tcu::ConstPixelBufferAccess resultAccess(tcuFormat, fbExtent, resolveBufferData);
368 
369         if (!tcu::floatThresholdCompare(log, "Result", "", geomColor, resultAccess, threshold,
370                                         tcu::COMPARE_LOG_ON_ERROR))
371             return tcu::TestStatus::fail("Unexpected color buffer results -- check log for details");
372     }
373     {
374         std::vector<uint32_t> counterResults(kNumDraws, 0u);
375         for (uint32_t drawIdx = 0u; drawIdx < kNumDraws; ++drawIdx)
376         {
377             const auto &bufferAlloc = counterBuffers.at(drawIdx)->getAllocation();
378             invalidateAlloc(ctx.vkd, ctx.device, bufferAlloc);
379             deMemcpy(&counterResults.at(drawIdx), bufferAlloc.getHostPtr(), sizeof(counterResults.at(drawIdx)));
380             log << tcu::TestLog::Message << "Draw " << drawIdx << ": " << counterResults.at(drawIdx) << " invocations"
381                 << tcu::TestLog::EndMessage;
382         }
383 
384         // The first result is run without sample shading enabled, so it can have any value from 1 to 4 invocations per pixel.
385         // The second result runs with sample shading enabled, so it must have exactly 4 invocations per pixel.
386         const uint32_t minInvs = (vkExtent.width * vkExtent.height) / 2u;
387         const uint32_t maxInvs = minInvs * static_cast<uint32_t>(kMultiSampleCount);
388 
389         verifyValueInRange(counterResults.at(0u), minInvs, maxInvs, "invocation counter without sample shading");
390         verifyValueInRange(counterResults.at(1u), maxInvs, maxInvs, "invocation counter with sample shading");
391     }
392 
393     return tcu::TestStatus::pass("Pass");
394 }
395 
396 #ifndef CTS_USES_VULKANSC
397 // Test that sample shading is enabled even if the sample count is dynamic and
398 // the product of minSampleShading and static sample count is not greater than
399 // 1.
400 //
401 // The backstory is that some drivers are known to have or have had an
402 // optimization where they enable sample shading like:
403 //
404 //  if (sampleShadingEnable && minSampleShading * rasterizationSamples > 1.0)
405 //
406 // In cases where rasterizationSamples is dynamic and only known at runtime,
407 // they may not enable sample rate shading. The tests will use a combination of
408 // minSampleShading and static rasterization sample count such that they're not
409 // over 1.0, but the dynamic sample count will make the number go over 1.0,
410 // requiring a minimum known sample count, verified using an atomic counter.
411 
412 namespace DSS // Dynamic Sample Shading
413 {
414 
415 constexpr VkFormat kFormat           = VK_FORMAT_R8G8B8A8_UNORM;
416 constexpr VkImageType kImageType     = VK_IMAGE_TYPE_2D;
417 constexpr VkImageViewType kViewType  = VK_IMAGE_VIEW_TYPE_2D;
418 constexpr VkImageTiling kTiling      = VK_IMAGE_TILING_OPTIMAL;
419 constexpr VkImageUsageFlags kMSUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; // Multisample. Single sample below.
420 constexpr VkImageUsageFlags kSSUsage =
421     (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
422 constexpr VkImageUsageFlags kTexUsage = (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
423 
424 struct Params
425 {
426     PipelineConstructionType constructionType;
427     VkSampleCountFlagBits staticCount;
428     VkSampleCountFlagBits dynamicCount;
429 };
430 
431 } // namespace DSS
432 
dynamicSampleShadingPrograms(SourceCollections & dst,DSS::Params)433 void dynamicSampleShadingPrograms(SourceCollections &dst, DSS::Params)
434 {
435     std::ostringstream vert;
436     vert << "#version 460\n"
437          << "layout (location=0) in vec4 inPos;\n"
438          << "layout (location=1) in vec2 inCoords;\n"
439          << "layout (location=0) out vec2 outCoords;\n"
440          << "void main (void) {\n"
441          << "    gl_Position = inPos;\n"
442          << "    outCoords   = inCoords;\n"
443          << "}\n";
444     dst.glslSources.add("vert") << glu::VertexSource(vert.str());
445 
446     // We use a flat-colored texture to avoid direct flat colors in the shader, in case it affects results.
447     std::ostringstream frag;
448     frag << "#version 460\n"
449          << "layout (location=0) out vec4 outColor;\n"
450          << "layout (location=0) in vec2 inCoords;\n"
451          << "layout (set=0, binding=0) uniform sampler2D tex;\n"
452          << "layout (set=0, binding=1, std430) buffer CounterBlock { uint counter; } atomicCounter;\n"
453          << "void main (void) {\n"
454          << "    outColor = texture(tex, inCoords);\n"
455          << "    atomicAdd(atomicCounter.counter, 1u);\n"
456          << "}\n";
457     dst.glslSources.add("frag") << glu::FragmentSource(frag.str());
458 }
459 
dynamicSampleShadingSupport(Context & context,DSS::Params params)460 void dynamicSampleShadingSupport(Context &context, DSS::Params params)
461 {
462     const auto &eds3Features = context.getExtendedDynamicState3FeaturesEXT();
463     if (!eds3Features.extendedDynamicState3RasterizationSamples)
464         TCU_THROW(NotSupportedError, "extendedDynamicState3RasterizationSamples not supported");
465 
466     const auto ctx              = context.getContextCommonData();
467     const auto formatProperties = getPhysicalDeviceImageFormatProperties(
468         ctx.vki, ctx.physicalDevice, DSS::kFormat, DSS::kImageType, DSS::kTiling, DSS::kMSUsage, 0u);
469     const auto expectedCounts = static_cast<VkSampleCountFlags>(params.staticCount | params.dynamicCount);
470 
471     if ((formatProperties.sampleCounts & expectedCounts) != expectedCounts)
472         TCU_THROW(NotSupportedError, "Sample counts not supported");
473 
474     context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_FRAGMENT_STORES_AND_ATOMICS);
475 }
476 
dynamicSampleShadingTest(Context & context,DSS::Params params)477 tcu::TestStatus dynamicSampleShadingTest(Context &context, DSS::Params params)
478 {
479     const auto &ctx = context.getContextCommonData();
480     const tcu::IVec3 fbExtent(2, 2, 1);
481     const auto vkExtent  = makeExtent3D(fbExtent);
482     const auto texExtent = makeExtent3D(16u, 16u, 1u);
483     const auto tcuFormat = mapVkFormat(DSS::kFormat);
484     const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
485     const tcu::Vec4 geomColor(0.0f, 0.0f, 1.0f, 1.0f);
486     const tcu::Vec4 threshold(0.0f, 0.0f, 0.0f, 0.0f); // When using 0 and 1 only, we expect exact results.
487     const auto bindPoint  = VK_PIPELINE_BIND_POINT_GRAPHICS;
488     const auto dataStages = VK_SHADER_STAGE_FRAGMENT_BIT;
489     const auto colorSRR   = makeDefaultImageSubresourceRange();
490 
491     // Multisample color buffer with verification buffer.
492     const VkImageCreateInfo msColorBufferCreateInfo = {
493         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
494         nullptr,                             // const void* pNext;
495         0u,                                  // VkImageCreateFlags flags;
496         DSS::kImageType,                     // VkImageType imageType;
497         DSS::kFormat,                        // VkFormat format;
498         vkExtent,                            // VkExtent3D extent;
499         1u,                                  // uint32_t mipLevels;
500         1u,                                  // uint32_t arrayLayers;
501         params.dynamicCount,                 // VkSampleCountFlagBits samples;
502         DSS::kTiling,                        // VkImageTiling tiling;
503         DSS::kMSUsage,                       // VkImageUsageFlags usage;
504         VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
505         1u,                                  // uint32_t queueFamilyIndexCount;
506         nullptr,                             // const uint32_t* pQueueFamilyIndices;
507         VK_IMAGE_LAYOUT_UNDEFINED,           // VkImageLayout initialLayout;
508     };
509     const auto msColorBuffer =
510         ImageWithMemory(ctx.vkd, ctx.device, ctx.allocator, msColorBufferCreateInfo, MemoryRequirement::Any);
511     const auto msColorBufferView =
512         makeImageView(ctx.vkd, ctx.device, *msColorBuffer, DSS::kViewType, DSS::kFormat, colorSRR);
513 
514     // Resolve attachment with verification buffer.
515     ImageWithBuffer colorBuffer(ctx.vkd, ctx.device, ctx.allocator, msColorBufferCreateInfo.extent,
516                                 msColorBufferCreateInfo.format, DSS::kSSUsage, msColorBufferCreateInfo.imageType,
517                                 colorSRR, msColorBufferCreateInfo.arrayLayers, VK_SAMPLE_COUNT_1_BIT,
518                                 msColorBufferCreateInfo.tiling);
519 
520     // Vertices.
521     struct VertexData
522     {
523         tcu::Vec4 position;
524         tcu::Vec2 texCoords;
525     };
526 
527     const std::vector<VertexData> vertices{
528         // Vertex position.                    Texture coordinates.
529         {tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec2(0.0f, 0.0f)},
530         {tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f), tcu::Vec2(0.0f, 1.0f)},
531         {tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec2(1.0f, 0.0f)},
532         {tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f), tcu::Vec2(1.0f, 1.0f)},
533     };
534 
535     // Vertex buffer
536     const auto vbSize = static_cast<VkDeviceSize>(de::dataSize(vertices));
537     const auto vbInfo = makeBufferCreateInfo(vbSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
538     BufferWithMemory vertexBuffer(ctx.vkd, ctx.device, ctx.allocator, vbInfo, MemoryRequirement::HostVisible);
539     const auto vbAlloc  = vertexBuffer.getAllocation();
540     void *vbData        = vbAlloc.getHostPtr();
541     const auto vbOffset = static_cast<VkDeviceSize>(0);
542 
543     deMemcpy(vbData, de::dataOrNull(vertices), de::dataSize(vertices));
544 
545     // Sampled texture.
546     const VkImageCreateInfo textureCreateInfo = {
547         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
548         nullptr,                             // const void* pNext;
549         0u,                                  // VkImageCreateFlags flags;
550         DSS::kImageType,                     // VkImageType imageType;
551         DSS::kFormat,                        // VkFormat format;
552         texExtent,                           // VkExtent3D extent;
553         1u,                                  // uint32_t mipLevels;
554         1u,                                  // uint32_t arrayLayers;
555         VK_SAMPLE_COUNT_1_BIT,               // VkSampleCountFlagBits samples;
556         DSS::kTiling,                        // VkImageTiling tiling;
557         DSS::kTexUsage,                      // VkImageUsageFlags usage;
558         VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
559         1u,                                  // uint32_t queueFamilyIndexCount;
560         nullptr,                             // const uint32_t* pQueueFamilyIndices;
561         VK_IMAGE_LAYOUT_UNDEFINED,           // VkImageLayout initialLayout;
562     };
563     const auto texture = ImageWithMemory(ctx.vkd, ctx.device, ctx.allocator, textureCreateInfo, MemoryRequirement::Any);
564     const auto textureView =
565         makeImageView(ctx.vkd, ctx.device, *texture, DSS::kViewType, textureCreateInfo.format, colorSRR);
566 
567     // Sampler.
568     const VkSamplerCreateInfo samplerCreateInfo = {
569         VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,   // VkStructureType sType;
570         nullptr,                                 // const void* pNext;
571         0u,                                      // VkSamplerCreateFlags flags;
572         VK_FILTER_NEAREST,                       // VkFilter magFilter;
573         VK_FILTER_NEAREST,                       // VkFilter minFilter;
574         VK_SAMPLER_MIPMAP_MODE_NEAREST,          // VkSamplerMipmapMode mipmapMode;
575         VK_SAMPLER_ADDRESS_MODE_REPEAT,          // VkSamplerAddressMode addressModeU;
576         VK_SAMPLER_ADDRESS_MODE_REPEAT,          // VkSamplerAddressMode addressModeV;
577         VK_SAMPLER_ADDRESS_MODE_REPEAT,          // VkSamplerAddressMode addressModeW;
578         0.0f,                                    // float mipLodBias;
579         VK_FALSE,                                // VkBool32 anisotropyEnable;
580         0.0f,                                    // float maxAnisotropy;
581         VK_FALSE,                                // VkBool32 compareEnable;
582         VK_COMPARE_OP_NEVER,                     // VkCompareOp compareOp;
583         0.0f,                                    // float minLod;
584         0.0f,                                    // float maxLod;
585         VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // VkBorderColor borderColor;
586         VK_FALSE,                                // VkBool32 unnormalizedCoordinates;
587     };
588     const auto sampler = createSampler(ctx.vkd, ctx.device, &samplerCreateInfo);
589 
590     // Atomic counter buffer.
591     const auto dbSize = static_cast<VkDeviceSize>(sizeof(uint32_t));
592     const auto dbInfo = makeBufferCreateInfo(dbSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
593     BufferWithMemory dataBuffer(ctx.vkd, ctx.device, ctx.allocator, dbInfo, MemoryRequirement::HostVisible);
594     const auto dbAlloc  = dataBuffer.getAllocation();
595     void *dbData        = dbAlloc.getHostPtr();
596     const auto dbOffset = static_cast<VkDeviceSize>(0);
597 
598     deMemset(dbData, 0, static_cast<size_t>(dbSize));
599 
600     // Descriptor pool, set, layout, etc.
601     DescriptorPoolBuilder poolBuilder;
602     poolBuilder.addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
603     poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
604     const auto descriptorPool =
605         poolBuilder.build(ctx.vkd, ctx.device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
606 
607     DescriptorSetLayoutBuilder layoutBuilder;
608     layoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, dataStages);
609     layoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, dataStages);
610     const auto setLayout     = layoutBuilder.build(ctx.vkd, ctx.device);
611     const auto descriptorSet = makeDescriptorSet(ctx.vkd, ctx.device, *descriptorPool, *setLayout);
612 
613     DescriptorSetUpdateBuilder updateBuilder;
614     const auto dbDescInfo  = makeDescriptorBufferInfo(dataBuffer.get(), dbOffset, dbSize);
615     const auto texDescInfo = makeDescriptorImageInfo(*sampler, *textureView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
616     updateBuilder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
617                               VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &texDescInfo);
618     updateBuilder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u),
619                               VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &dbDescInfo);
620     updateBuilder.update(ctx.vkd, ctx.device);
621 
622     const auto pipelineLayout = PipelineLayoutWrapper(params.constructionType, ctx.vkd, ctx.device, *setLayout);
623 
624     const std::vector<VkAttachmentDescription> attachmentDescriptions{
625         makeAttachmentDescription( // Multisample attachment.
626             0u, DSS::kFormat, params.dynamicCount, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_DONT_CARE,
627             VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_UNDEFINED,
628             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL),
629         makeAttachmentDescription( // Resolve attachment.
630             0u, DSS::kFormat, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_STORE,
631             VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_UNDEFINED,
632             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL),
633     };
634 
635     const std::vector<VkAttachmentReference> attachmentReferences{
636         makeAttachmentReference(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL), // Multisample.
637         makeAttachmentReference(1u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL), // Resolve.
638     };
639 
640     const auto subpass = makeSubpassDescription(0u, bindPoint, 0u, nullptr, 1u, &attachmentReferences.at(0u),
641                                                 &attachmentReferences.at(1u), nullptr, 0u, nullptr);
642 
643     const VkRenderPassCreateInfo renderPassCreateInfo = {
644         VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
645         nullptr,                                   // const void* pNext;
646         0u,                                        // VkRenderPassCreateFlags flags;
647         de::sizeU32(attachmentDescriptions),       // uint32_t attachmentCount;
648         de::dataOrNull(attachmentDescriptions),    // const VkAttachmentDescription* pAttachments;
649         1u,                                        // uint32_t subpassCount;
650         &subpass,                                  // const VkSubpassDescription* pSubpasses;
651         0u,                                        // uint32_t dependencyCount;
652         nullptr,                                   // const VkSubpassDependency* pDependencies;
653     };
654     auto renderPass = RenderPassWrapper(params.constructionType, ctx.vkd, ctx.device, &renderPassCreateInfo);
655 
656     const std::vector<VkImage> fbImages{*msColorBuffer, colorBuffer.getImage()};
657     const std::vector<VkImageView> fbImageViews{*msColorBufferView, colorBuffer.getImageView()};
658     DE_ASSERT(fbImages.size() == fbImageViews.size());
659     renderPass.createFramebuffer(ctx.vkd, ctx.device, de::sizeU32(fbImageViews), de::dataOrNull(fbImages),
660                                  de::dataOrNull(fbImageViews), vkExtent.width, vkExtent.height);
661 
662     // Modules.
663     const auto &binaries  = context.getBinaryCollection();
664     const auto vertModule = ShaderWrapper(ctx.vkd, ctx.device, binaries.get("vert"));
665     const auto fragModule = ShaderWrapper(ctx.vkd, ctx.device, binaries.get("frag"));
666 
667     const std::vector<VkViewport> viewports(1u, makeViewport(vkExtent));
668     const std::vector<VkRect2D> scissors(1u, makeRect2D(vkExtent));
669 
670     const std::vector<VkDynamicState> dynamicStates{VK_DYNAMIC_STATE_RASTERIZATION_SAMPLES_EXT};
671 
672     VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo = initVulkanStructure();
673     dynamicStateCreateInfo.dynamicStateCount                = de::sizeU32(dynamicStates);
674     dynamicStateCreateInfo.pDynamicStates                   = de::dataOrNull(dynamicStates);
675 
676     const std::vector<VkVertexInputBindingDescription> bindingDescriptions{
677         makeVertexInputBindingDescription(0u, static_cast<uint32_t>(sizeof(VertexData)), VK_VERTEX_INPUT_RATE_VERTEX),
678     };
679 
680     const std::vector<VkVertexInputAttributeDescription> attributeDescriptions{
681         makeVertexInputAttributeDescription(0u, 0u, vk::VK_FORMAT_R32G32B32A32_SFLOAT,
682                                             static_cast<uint32_t>(offsetof(VertexData, position))),
683         makeVertexInputAttributeDescription(1u, 0u, vk::VK_FORMAT_R32G32_SFLOAT,
684                                             static_cast<uint32_t>(offsetof(VertexData, texCoords))),
685     };
686 
687     VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = initVulkanStructure();
688     vertexInputStateCreateInfo.vertexBindingDescriptionCount        = de::sizeU32(bindingDescriptions);
689     vertexInputStateCreateInfo.pVertexBindingDescriptions           = de::dataOrNull(bindingDescriptions);
690     vertexInputStateCreateInfo.vertexAttributeDescriptionCount      = de::sizeU32(attributeDescriptions);
691     vertexInputStateCreateInfo.pVertexAttributeDescriptions         = de::dataOrNull(attributeDescriptions);
692 
693     // This is critical for the test. We need to select a minSampleShading value
694     // that results in <= 1.0 when multiplied with the static sample count, but
695     // > 1.0 when using the dynamic sample count.
696     const auto minSampleShading = 1.0f / static_cast<float>(params.staticCount);
697 
698     VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo = initVulkanStructure();
699     multisampleStateCreateInfo.rasterizationSamples                 = params.staticCount;
700     multisampleStateCreateInfo.sampleShadingEnable                  = VK_TRUE;
701     multisampleStateCreateInfo.minSampleShading                     = minSampleShading;
702 
703     GraphicsPipelineWrapper pipeline(ctx.vki, ctx.vkd, ctx.physicalDevice, ctx.device, context.getDeviceExtensions(),
704                                      params.constructionType);
705     pipeline.setDefaultTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)
706         .setDefaultRasterizationState()
707         .setDefaultColorBlendState()
708         .setDynamicState(&dynamicStateCreateInfo)
709         .setupVertexInputState(&vertexInputStateCreateInfo)
710         .setupPreRasterizationShaderState(viewports, scissors, pipelineLayout, *renderPass, 0u, vertModule)
711         .setupFragmentShaderState(pipelineLayout, *renderPass, 0u, fragModule, nullptr, &multisampleStateCreateInfo)
712         .setupFragmentOutputState(*renderPass, 0u, nullptr, &multisampleStateCreateInfo)
713         .setMonolithicPipelineLayout(pipelineLayout)
714         .buildPipeline();
715 
716     CommandPoolWithBuffer cmd(ctx.vkd, ctx.device, ctx.qfIndex);
717     const auto cmdBuffer = *cmd.cmdBuffer;
718 
719     beginCommandBuffer(ctx.vkd, cmdBuffer);
720 
721     // Clear texture to the geometry color.
722     {
723         const auto preClearBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
724                                                             VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, *texture, colorSRR);
725         cmdPipelineImageMemoryBarrier(ctx.vkd, cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
726                                       VK_PIPELINE_STAGE_TRANSFER_BIT, &preClearBarrier);
727         const auto texClearColor = makeClearValueColor(geomColor);
728         ctx.vkd.cmdClearColorImage(cmdBuffer, *texture, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &texClearColor.color, 1u,
729                                    &colorSRR);
730         const auto postClearBarrier = makeImageMemoryBarrier(
731             VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
732             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, *texture, colorSRR);
733         cmdPipelineImageMemoryBarrier(ctx.vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT,
734                                       VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, &postClearBarrier);
735     }
736 
737     const auto clearValue = makeClearValueColor(clearColor);
738     renderPass.begin(ctx.vkd, cmdBuffer, scissors.at(0u), clearValue);
739     ctx.vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vbOffset);
740     ctx.vkd.cmdBindDescriptorSets(cmdBuffer, bindPoint, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, nullptr);
741     pipeline.bind(cmdBuffer);
742     ctx.vkd.cmdSetRasterizationSamplesEXT(cmdBuffer, params.dynamicCount);
743     ctx.vkd.cmdDraw(cmdBuffer, de::sizeU32(vertices), 1u, 0u, 0u);
744     renderPass.end(ctx.vkd, cmdBuffer);
745     copyImageToBuffer(ctx.vkd, cmdBuffer, colorBuffer.getImage(), colorBuffer.getBuffer(), fbExtent.swizzle(0, 1),
746                       VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1u,
747                       VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_ASPECT_COLOR_BIT,
748                       VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
749     {
750         const auto atomicDataBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
751         cmdPipelineMemoryBarrier(ctx.vkd, cmdBuffer, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT,
752                                  &atomicDataBarrier);
753     }
754     endCommandBuffer(ctx.vkd, cmdBuffer);
755     submitCommandsAndWait(ctx.vkd, ctx.device, ctx.queue, cmdBuffer);
756 
757     // Verify color output.
758     invalidateAlloc(ctx.vkd, ctx.device, colorBuffer.getBufferAllocation());
759     tcu::PixelBufferAccess resultAccess(tcuFormat, fbExtent, colorBuffer.getBufferAllocation().getHostPtr());
760 
761     tcu::TextureLevel referenceLevel(tcuFormat, fbExtent.x(), fbExtent.y());
762     auto referenceAccess = referenceLevel.getAccess();
763     tcu::clear(referenceAccess, geomColor);
764 
765     auto &log = context.getTestContext().getLog();
766     if (!tcu::floatThresholdCompare(log, "Result", "", referenceAccess, resultAccess, threshold,
767                                     tcu::COMPARE_LOG_ON_ERROR))
768         return tcu::TestStatus::fail("Unexpected color in result buffer; check log for details");
769 
770     // Verify actual sample count.
771     const uint32_t minCountPerPixel = static_cast<uint32_t>(minSampleShading * static_cast<float>(params.dynamicCount));
772     const uint32_t pixelCount       = vkExtent.width * vkExtent.height;
773     const uint32_t minExpectedCount = pixelCount * minCountPerPixel;
774     uint32_t resultCount            = 0u;
775 
776     invalidateAlloc(ctx.vkd, ctx.device, dbAlloc);
777     deMemcpy(&resultCount, dbData, sizeof(resultCount));
778 
779     if (resultCount < minExpectedCount)
780     {
781         std::ostringstream msg;
782         msg << "Unexpected fragment shader count: expected at least " << minExpectedCount << " but found "
783             << resultCount;
784         TCU_FAIL(msg.str());
785     }
786 
787     return tcu::TestStatus::pass("Pass");
788 }
789 #endif // CTS_USES_VULKANSC
790 
791 using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
792 
793 } // anonymous namespace
794 
createExtendedDynamicStateMiscTests(tcu::TestContext & testCtx,vk::PipelineConstructionType pipelineConstructionType)795 tcu::TestCaseGroup *createExtendedDynamicStateMiscTests(tcu::TestContext &testCtx,
796                                                         vk::PipelineConstructionType pipelineConstructionType)
797 {
798     GroupPtr miscGroup(new tcu::TestCaseGroup(testCtx, "misc"));
799 
800     addFunctionCaseWithPrograms(miscGroup.get(), "sample_shading_dynamic_sample_count",
801                                 sampleShadingWithDynamicSampleCountSupport, sampleShadingWithDynamicSampleCountPrograms,
802                                 sampleShadingWithDynamicSampleCount, pipelineConstructionType);
803 
804 #ifndef CTS_USES_VULKANSC
805     if (!isConstructionTypeShaderObject(pipelineConstructionType))
806     {
807         const std::vector<VkSampleCountFlagBits> sampleCounts{
808             VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_2_BIT,  VK_SAMPLE_COUNT_4_BIT,
809             VK_SAMPLE_COUNT_8_BIT, VK_SAMPLE_COUNT_16_BIT,
810         };
811 
812         for (size_t i = 0; i < sampleCounts.size(); ++i)
813             for (size_t j = i + 1; j < sampleCounts.size(); ++j)
814             {
815                 const auto staticCount = sampleCounts.at(i);
816                 const auto dynamicCount =
817                     sampleCounts.at(j); // The actual dynamic count is always greater than the static value.
818 
819                 const DSS::Params params{
820                     pipelineConstructionType,
821                     staticCount,
822                     dynamicCount,
823                 };
824                 const auto testName = "dynamic_sample_shading_static_" + std::to_string(staticCount) + "_dynamic_" +
825                                       std::to_string(dynamicCount);
826                 addFunctionCaseWithPrograms(miscGroup.get(), testName, dynamicSampleShadingSupport,
827                                             dynamicSampleShadingPrograms, dynamicSampleShadingTest, params);
828             }
829     }
830 #endif // CTS_USES_VULKANSC
831 
832     return miscGroup.release();
833 }
834 
835 } // namespace pipeline
836 } // namespace vkt
837