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