1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2016 The Khronos Group Inc.
6 * Copyright (c) 2023 LunarG, Inc.
7 * Copyright (c) 2023 Nintendo
8 *
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 *
21 *//*
22 * \file vktPipelineMultisampleShaderBuiltInTests.cpp
23 * \brief Multisample Shader BuiltIn Tests
24 *//*--------------------------------------------------------------------*/
25
26 #include "vktPipelineMultisampleShaderBuiltInTests.hpp"
27 #include "vktPipelineMultisampleBaseResolveAndPerSampleFetch.hpp"
28 #include "vktPipelineMakeUtil.hpp"
29
30 #include "vkBuilderUtil.hpp"
31 #include "vkQueryUtil.hpp"
32 #include "vkObjUtil.hpp"
33 #include "vkImageWithMemory.hpp"
34 #include "vkBufferWithMemory.hpp"
35 #include "vkBarrierUtil.hpp"
36 #include "vkCmdUtil.hpp"
37 #include "vkTypeUtil.hpp"
38
39 #include "tcuVectorUtil.hpp"
40 #include "tcuTestLog.hpp"
41
42 #include <set>
43 #include <cmath>
44
45 using std::set;
46
47 namespace vkt
48 {
49 namespace pipeline
50 {
51 namespace multisample
52 {
53
54 using namespace vk;
55
56 struct VertexDataNdc
57 {
VertexDataNdcvkt::pipeline::multisample::VertexDataNdc58 VertexDataNdc(const tcu::Vec4 &posNdc) : positionNdc(posNdc)
59 {
60 }
61
62 tcu::Vec4 positionNdc;
63 };
64
getVertexDataDescriptonNdc(void)65 MultisampleInstanceBase::VertexDataDesc getVertexDataDescriptonNdc(void)
66 {
67 MultisampleInstanceBase::VertexDataDesc vertexDataDesc;
68
69 vertexDataDesc.verticesCount = 4u;
70 vertexDataDesc.dataStride = sizeof(VertexDataNdc);
71 vertexDataDesc.dataSize = vertexDataDesc.verticesCount * vertexDataDesc.dataStride;
72 vertexDataDesc.primitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
73
74 const VkVertexInputAttributeDescription vertexAttribPositionNdc = {
75 0u, // uint32_t location;
76 0u, // uint32_t binding;
77 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
78 offsetof(VertexDataNdc, positionNdc), // uint32_t offset;
79 };
80
81 vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionNdc);
82
83 return vertexDataDesc;
84 }
85
uploadVertexDataNdc(const Allocation & vertexBufferAllocation,const MultisampleInstanceBase::VertexDataDesc & vertexDataDescripton)86 void uploadVertexDataNdc(const Allocation &vertexBufferAllocation,
87 const MultisampleInstanceBase::VertexDataDesc &vertexDataDescripton)
88 {
89 std::vector<VertexDataNdc> vertices;
90
91 vertices.push_back(VertexDataNdc(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f)));
92 vertices.push_back(VertexDataNdc(tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f)));
93 vertices.push_back(VertexDataNdc(tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f)));
94 vertices.push_back(VertexDataNdc(tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f)));
95
96 deMemcpy(vertexBufferAllocation.getHostPtr(), dataPointer(vertices),
97 static_cast<std::size_t>(vertexDataDescripton.dataSize));
98 }
99
100 struct VertexDataNdcScreen
101 {
VertexDataNdcScreenvkt::pipeline::multisample::VertexDataNdcScreen102 VertexDataNdcScreen(const tcu::Vec4 &posNdc, const tcu::Vec2 &posScreen)
103 : positionNdc(posNdc)
104 , positionScreen(posScreen)
105 {
106 }
107
108 tcu::Vec4 positionNdc;
109 tcu::Vec2 positionScreen;
110 };
111
getVertexDataDescriptonNdcScreen(void)112 MultisampleInstanceBase::VertexDataDesc getVertexDataDescriptonNdcScreen(void)
113 {
114 MultisampleInstanceBase::VertexDataDesc vertexDataDesc;
115
116 vertexDataDesc.verticesCount = 4u;
117 vertexDataDesc.dataStride = sizeof(VertexDataNdcScreen);
118 vertexDataDesc.dataSize = vertexDataDesc.verticesCount * vertexDataDesc.dataStride;
119 vertexDataDesc.primitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
120
121 const VkVertexInputAttributeDescription vertexAttribPositionNdc = {
122 0u, // uint32_t location;
123 0u, // uint32_t binding;
124 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
125 offsetof(VertexDataNdcScreen, positionNdc), // uint32_t offset;
126 };
127
128 vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionNdc);
129
130 const VkVertexInputAttributeDescription vertexAttribPositionScreen = {
131 1u, // uint32_t location;
132 0u, // uint32_t binding;
133 VK_FORMAT_R32G32_SFLOAT, // VkFormat format;
134 offsetof(VertexDataNdcScreen, positionScreen), // uint32_t offset;
135 };
136
137 vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionScreen);
138
139 return vertexDataDesc;
140 }
141
uploadVertexDataNdcScreen(const Allocation & vertexBufferAllocation,const MultisampleInstanceBase::VertexDataDesc & vertexDataDescripton,const tcu::Vec2 & screenSize)142 void uploadVertexDataNdcScreen(const Allocation &vertexBufferAllocation,
143 const MultisampleInstanceBase::VertexDataDesc &vertexDataDescripton,
144 const tcu::Vec2 &screenSize)
145 {
146 std::vector<VertexDataNdcScreen> vertices;
147
148 vertices.push_back(VertexDataNdcScreen(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec2(0.0f, 0.0f)));
149 vertices.push_back(VertexDataNdcScreen(tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec2(screenSize.x(), 0.0f)));
150 vertices.push_back(VertexDataNdcScreen(tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f), tcu::Vec2(0.0f, screenSize.y())));
151 vertices.push_back(
152 VertexDataNdcScreen(tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f), tcu::Vec2(screenSize.x(), screenSize.y())));
153
154 deMemcpy(vertexBufferAllocation.getHostPtr(), dataPointer(vertices),
155 static_cast<std::size_t>(vertexDataDescripton.dataSize));
156 }
157
checkForErrorMS(const vk::VkImageCreateInfo & imageMSInfo,const std::vector<tcu::ConstPixelBufferAccess> & dataPerSample,const uint32_t errorCompNdx)158 bool checkForErrorMS(const vk::VkImageCreateInfo &imageMSInfo,
159 const std::vector<tcu::ConstPixelBufferAccess> &dataPerSample, const uint32_t errorCompNdx)
160 {
161 const uint32_t numSamples = static_cast<uint32_t>(imageMSInfo.samples);
162
163 for (uint32_t z = 0u; z < imageMSInfo.extent.depth; ++z)
164 for (uint32_t y = 0u; y < imageMSInfo.extent.height; ++y)
165 for (uint32_t x = 0u; x < imageMSInfo.extent.width; ++x)
166 {
167 for (uint32_t sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
168 {
169 const uint32_t errorComponent = dataPerSample[sampleNdx].getPixelUint(x, y, z)[errorCompNdx];
170
171 if (errorComponent > 0)
172 return true;
173 }
174 }
175
176 return false;
177 }
178
checkForErrorRS(const vk::VkImageCreateInfo & imageRSInfo,const tcu::ConstPixelBufferAccess & dataRS,const uint32_t errorCompNdx)179 bool checkForErrorRS(const vk::VkImageCreateInfo &imageRSInfo, const tcu::ConstPixelBufferAccess &dataRS,
180 const uint32_t errorCompNdx)
181 {
182 for (uint32_t z = 0u; z < imageRSInfo.extent.depth; ++z)
183 for (uint32_t y = 0u; y < imageRSInfo.extent.height; ++y)
184 for (uint32_t x = 0u; x < imageRSInfo.extent.width; ++x)
185 {
186 const uint32_t errorComponent = dataRS.getPixelUint(x, y, z)[errorCompNdx];
187
188 if (errorComponent > 0)
189 return true;
190 }
191
192 return false;
193 }
194
195 template <typename CaseClassName>
196 class MSCase : public MSCaseBaseResolveAndPerSampleFetch
197 {
198 public:
MSCase(tcu::TestContext & testCtx,const std::string & name,const ImageMSParams & imageMSParams)199 MSCase(tcu::TestContext &testCtx, const std::string &name, const ImageMSParams &imageMSParams)
200 : MSCaseBaseResolveAndPerSampleFetch(testCtx, name, imageMSParams)
201 {
202 }
203
204 virtual void checkSupport(Context &context) const;
205 void init(void);
206 void initPrograms(vk::SourceCollections &programCollection) const;
207 TestInstance *createInstance(Context &context) const;
208 static MultisampleCaseBase *createCase(tcu::TestContext &testCtx, const std::string &name,
209 const ImageMSParams &imageMSParams);
210 };
211 #ifndef CTS_USES_VULKANSC
212 template <typename CaseClassName>
checkSupport(Context & context) const213 void MSCase<CaseClassName>::checkSupport(Context &context) const
214 {
215 checkGraphicsPipelineLibrarySupport(context);
216 }
217 #endif // CTS_USES_VULKANSC
218
219 template <typename CaseClassName>
createCase(tcu::TestContext & testCtx,const std::string & name,const ImageMSParams & imageMSParams)220 MultisampleCaseBase *MSCase<CaseClassName>::createCase(tcu::TestContext &testCtx, const std::string &name,
221 const ImageMSParams &imageMSParams)
222 {
223 return new MSCase<CaseClassName>(testCtx, name, imageMSParams);
224 }
225
226 template <typename InstanceClassName>
227 class MSInstance : public MSInstanceBaseResolveAndPerSampleFetch
228 {
229 public:
MSInstance(Context & context,const ImageMSParams & imageMSParams)230 MSInstance(Context &context, const ImageMSParams &imageMSParams)
231 : MSInstanceBaseResolveAndPerSampleFetch(context, imageMSParams)
232 {
233 }
234
235 VertexDataDesc getVertexDataDescripton(void) const;
236 void uploadVertexData(const Allocation &vertexBufferAllocation, const VertexDataDesc &vertexDataDescripton) const;
237
238 tcu::TestStatus verifyImageData(const vk::VkImageCreateInfo &imageMSInfo, const vk::VkImageCreateInfo &imageRSInfo,
239 const std::vector<tcu::ConstPixelBufferAccess> &dataPerSample,
240 const tcu::ConstPixelBufferAccess &dataRS) const;
241
getMSStateCreateInfo(const ImageMSParams & imageMSParams) const242 virtual VkPipelineMultisampleStateCreateInfo getMSStateCreateInfo(const ImageMSParams &imageMSParams) const
243 {
244 return MSInstanceBaseResolveAndPerSampleFetch::getMSStateCreateInfo(imageMSParams);
245 }
246 };
247
248 class MSInstanceSampleID;
249
250 template <>
getVertexDataDescripton(void) const251 MultisampleInstanceBase::VertexDataDesc MSInstance<MSInstanceSampleID>::getVertexDataDescripton(void) const
252 {
253 return getVertexDataDescriptonNdc();
254 }
255
256 template <>
uploadVertexData(const Allocation & vertexBufferAllocation,const VertexDataDesc & vertexDataDescripton) const257 void MSInstance<MSInstanceSampleID>::uploadVertexData(const Allocation &vertexBufferAllocation,
258 const VertexDataDesc &vertexDataDescripton) const
259 {
260 uploadVertexDataNdc(vertexBufferAllocation, vertexDataDescripton);
261 }
262
263 template <>
verifyImageData(const vk::VkImageCreateInfo & imageMSInfo,const vk::VkImageCreateInfo & imageRSInfo,const std::vector<tcu::ConstPixelBufferAccess> & dataPerSample,const tcu::ConstPixelBufferAccess & dataRS) const264 tcu::TestStatus MSInstance<MSInstanceSampleID>::verifyImageData(
265 const vk::VkImageCreateInfo &imageMSInfo, const vk::VkImageCreateInfo &imageRSInfo,
266 const std::vector<tcu::ConstPixelBufferAccess> &dataPerSample, const tcu::ConstPixelBufferAccess &dataRS) const
267 {
268 DE_UNREF(imageRSInfo);
269 DE_UNREF(dataRS);
270
271 const uint32_t numSamples = static_cast<uint32_t>(imageMSInfo.samples);
272
273 for (uint32_t sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
274 {
275 for (uint32_t z = 0u; z < imageMSInfo.extent.depth; ++z)
276 for (uint32_t y = 0u; y < imageMSInfo.extent.height; ++y)
277 for (uint32_t x = 0u; x < imageMSInfo.extent.width; ++x)
278 {
279 const uint32_t sampleID = dataPerSample[sampleNdx].getPixelUint(x, y, z).x();
280
281 if (sampleID != sampleNdx)
282 return tcu::TestStatus::fail("gl_SampleID does not have correct value");
283 }
284 }
285
286 return tcu::TestStatus::pass("Passed");
287 }
288
289 class MSCaseSampleID;
290
291 template <>
checkSupport(Context & context) const292 void MSCase<MSCaseSampleID>::checkSupport(Context &context) const
293 {
294 checkGraphicsPipelineLibrarySupport(context);
295 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SAMPLE_RATE_SHADING);
296 }
297
298 template <>
init(void)299 void MSCase<MSCaseSampleID>::init(void)
300 {
301 m_testCtx.getLog() << tcu::TestLog::Message
302 << "Writing gl_SampleID to the red channel of the texture and verifying texture values.\n"
303 << "Expecting value N at sample index N of a multisample texture.\n"
304 << tcu::TestLog::EndMessage;
305
306 MultisampleCaseBase::init();
307 }
308
309 template <>
initPrograms(vk::SourceCollections & programCollection) const310 void MSCase<MSCaseSampleID>::initPrograms(vk::SourceCollections &programCollection) const
311 {
312 MSCaseBaseResolveAndPerSampleFetch::initPrograms(programCollection);
313
314 // Create vertex shader
315 std::ostringstream vs;
316
317 vs << "#version 440\n"
318 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
319 << "\n"
320 << "out gl_PerVertex {\n"
321 << " vec4 gl_Position;\n"
322 << "};\n"
323 << "void main (void)\n"
324 << "{\n"
325 << " gl_Position = vs_in_position_ndc;\n"
326 << "}\n";
327
328 programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
329
330 // Create fragment shader
331 std::ostringstream fs;
332
333 fs << "#version 440\n"
334 << "\n"
335 << "layout(location = 0) out vec4 fs_out_color;\n"
336 << "\n"
337 << "void main (void)\n"
338 << "{\n"
339 << " fs_out_color = vec4(float(gl_SampleID) / float(255), 0.0, 0.0, 1.0);\n"
340 << "}\n";
341
342 programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
343 }
344
345 template <>
createInstance(Context & context) const346 TestInstance *MSCase<MSCaseSampleID>::createInstance(Context &context) const
347 {
348 return new MSInstance<MSInstanceSampleID>(context, m_imageMSParams);
349 }
350
351 class MSInstanceSamplePosDistribution;
352
353 template <>
getVertexDataDescripton(void) const354 MultisampleInstanceBase::VertexDataDesc MSInstance<MSInstanceSamplePosDistribution>::getVertexDataDescripton(void) const
355 {
356 return getVertexDataDescriptonNdc();
357 }
358
359 template <>
uploadVertexData(const Allocation & vertexBufferAllocation,const VertexDataDesc & vertexDataDescripton) const360 void MSInstance<MSInstanceSamplePosDistribution>::uploadVertexData(const Allocation &vertexBufferAllocation,
361 const VertexDataDesc &vertexDataDescripton) const
362 {
363 uploadVertexDataNdc(vertexBufferAllocation, vertexDataDescripton);
364 }
365
366 template <>
verifyImageData(const vk::VkImageCreateInfo & imageMSInfo,const vk::VkImageCreateInfo & imageRSInfo,const std::vector<tcu::ConstPixelBufferAccess> & dataPerSample,const tcu::ConstPixelBufferAccess & dataRS) const367 tcu::TestStatus MSInstance<MSInstanceSamplePosDistribution>::verifyImageData(
368 const vk::VkImageCreateInfo &imageMSInfo, const vk::VkImageCreateInfo &imageRSInfo,
369 const std::vector<tcu::ConstPixelBufferAccess> &dataPerSample, const tcu::ConstPixelBufferAccess &dataRS) const
370 {
371 const uint32_t numSamples = static_cast<uint32_t>(imageMSInfo.samples);
372
373 // approximate Bates distribution as normal
374 const float variance = (1.0f / (12.0f * (float)numSamples));
375 const float standardDeviation = deFloatSqrt(variance);
376
377 // 95% of means of sample positions are within 2 standard deviations if
378 // they were randomly assigned. Sample patterns are expected to be more
379 // uniform than a random pattern.
380 const float distanceThreshold = 2.0f * standardDeviation;
381
382 for (uint32_t z = 0u; z < imageRSInfo.extent.depth; ++z)
383 for (uint32_t y = 0u; y < imageRSInfo.extent.height; ++y)
384 for (uint32_t x = 0u; x < imageRSInfo.extent.width; ++x)
385 {
386 const uint32_t errorComponent = dataRS.getPixelUint(x, y, z).z();
387
388 if (errorComponent > 0)
389 return tcu::TestStatus::fail("gl_SamplePosition is not within interval [0,1]");
390
391 if (numSamples >= VK_SAMPLE_COUNT_4_BIT)
392 {
393 const tcu::Vec2 averageSamplePos = tcu::Vec2((float)dataRS.getPixelUint(x, y, z).x() / 255.0f,
394 (float)dataRS.getPixelUint(x, y, z).y() / 255.0f);
395 const tcu::Vec2 distanceFromCenter = tcu::abs(averageSamplePos - tcu::Vec2(0.5f, 0.5f));
396
397 if (distanceFromCenter.x() > distanceThreshold || distanceFromCenter.y() > distanceThreshold)
398 return tcu::TestStatus::fail("Sample positions are not uniformly distributed within the pixel");
399 }
400 }
401
402 for (uint32_t z = 0u; z < imageMSInfo.extent.depth; ++z)
403 for (uint32_t y = 0u; y < imageMSInfo.extent.height; ++y)
404 for (uint32_t x = 0u; x < imageMSInfo.extent.width; ++x)
405 {
406 std::vector<tcu::Vec2> samplePositions(numSamples);
407
408 for (uint32_t sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
409 {
410 const uint32_t errorComponent = dataPerSample[sampleNdx].getPixelUint(x, y, z).z();
411
412 if (errorComponent > 0)
413 return tcu::TestStatus::fail("gl_SamplePosition is not within interval [0,1]");
414
415 samplePositions[sampleNdx] =
416 tcu::Vec2((float)dataPerSample[sampleNdx].getPixelUint(x, y, z).x() / 255.0f,
417 (float)dataPerSample[sampleNdx].getPixelUint(x, y, z).y() / 255.0f);
418 }
419
420 for (uint32_t sampleNdxA = 0u; sampleNdxA < numSamples; ++sampleNdxA)
421 for (uint32_t sampleNdxB = sampleNdxA + 1u; sampleNdxB < numSamples; ++sampleNdxB)
422 {
423 if (samplePositions[sampleNdxA] == samplePositions[sampleNdxB])
424 return tcu::TestStatus::fail("Two samples have the same position");
425 }
426
427 if (numSamples >= VK_SAMPLE_COUNT_4_BIT)
428 {
429 tcu::Vec2 averageSamplePos(0.0f, 0.0f);
430
431 for (uint32_t sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
432 {
433 averageSamplePos.x() += samplePositions[sampleNdx].x();
434 averageSamplePos.y() += samplePositions[sampleNdx].y();
435 }
436
437 averageSamplePos.x() /= (float)numSamples;
438 averageSamplePos.y() /= (float)numSamples;
439
440 const tcu::Vec2 distanceFromCenter = tcu::abs(averageSamplePos - tcu::Vec2(0.5f, 0.5f));
441
442 if (distanceFromCenter.x() > distanceThreshold || distanceFromCenter.y() > distanceThreshold)
443 return tcu::TestStatus::fail("Sample positions are not uniformly distributed within the pixel");
444 }
445 }
446
447 return tcu::TestStatus::pass("Passed");
448 }
449
450 class MSCaseSamplePosDistribution;
451
452 template <>
checkSupport(Context & context) const453 void MSCase<MSCaseSamplePosDistribution>::checkSupport(Context &context) const
454 {
455 checkGraphicsPipelineLibrarySupport(context);
456 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SAMPLE_RATE_SHADING);
457 }
458
459 template <>
init(void)460 void MSCase<MSCaseSamplePosDistribution>::init(void)
461 {
462 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying gl_SamplePosition value with multisample targets:\n"
463 << " a) Expect legal sample position.\n"
464 << " b) Sample position is unique within the set of all sample positions of a pixel.\n"
465 << " c) Sample position distribution is uniform or almost uniform.\n"
466 << tcu::TestLog::EndMessage;
467
468 MultisampleCaseBase::init();
469 }
470
471 template <>
initPrograms(vk::SourceCollections & programCollection) const472 void MSCase<MSCaseSamplePosDistribution>::initPrograms(vk::SourceCollections &programCollection) const
473 {
474 MSCaseBaseResolveAndPerSampleFetch::initPrograms(programCollection);
475
476 // Create vertex shader
477 std::ostringstream vs;
478
479 vs << "#version 440\n"
480 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
481 << "\n"
482 << "out gl_PerVertex {\n"
483 << " vec4 gl_Position;\n"
484 << "};\n"
485 << "void main (void)\n"
486 << "{\n"
487 << " gl_Position = vs_in_position_ndc;\n"
488 << "}\n";
489
490 programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
491
492 // Create fragment shader
493 std::ostringstream fs;
494
495 fs << "#version 440\n"
496 << "\n"
497 << "layout(location = 0) out vec4 fs_out_color;\n"
498 << "\n"
499 << "void main (void)\n"
500 << "{\n"
501 << " if (gl_SamplePosition.x < 0.0 || gl_SamplePosition.x > 1.0 || gl_SamplePosition.y < 0.0 || "
502 "gl_SamplePosition.y > 1.0)\n"
503 " fs_out_color = vec4(0.0, 0.0, 1.0, 1.0);\n"
504 " else\n"
505 " fs_out_color = vec4(gl_SamplePosition.x, gl_SamplePosition.y, 0.0, 1.0);\n"
506 "}\n";
507
508 programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
509 }
510
511 template <>
createInstance(Context & context) const512 TestInstance *MSCase<MSCaseSamplePosDistribution>::createInstance(Context &context) const
513 {
514 return new MSInstance<MSInstanceSamplePosDistribution>(context, m_imageMSParams);
515 }
516
517 class MSInstanceSamplePosCorrectness;
518
519 template <>
getVertexDataDescripton(void) const520 MultisampleInstanceBase::VertexDataDesc MSInstance<MSInstanceSamplePosCorrectness>::getVertexDataDescripton(void) const
521 {
522 return getVertexDataDescriptonNdcScreen();
523 }
524
525 template <>
uploadVertexData(const Allocation & vertexBufferAllocation,const VertexDataDesc & vertexDataDescripton) const526 void MSInstance<MSInstanceSamplePosCorrectness>::uploadVertexData(const Allocation &vertexBufferAllocation,
527 const VertexDataDesc &vertexDataDescripton) const
528 {
529 const tcu::UVec3 layerSize = getLayerSize(IMAGE_TYPE_2D, m_imageMSParams.imageSize);
530
531 uploadVertexDataNdcScreen(vertexBufferAllocation, vertexDataDescripton,
532 tcu::Vec2(static_cast<float>(layerSize.x()), static_cast<float>(layerSize.y())));
533 }
534
535 template <>
verifyImageData(const vk::VkImageCreateInfo & imageMSInfo,const vk::VkImageCreateInfo & imageRSInfo,const std::vector<tcu::ConstPixelBufferAccess> & dataPerSample,const tcu::ConstPixelBufferAccess & dataRS) const536 tcu::TestStatus MSInstance<MSInstanceSamplePosCorrectness>::verifyImageData(
537 const vk::VkImageCreateInfo &imageMSInfo, const vk::VkImageCreateInfo &imageRSInfo,
538 const std::vector<tcu::ConstPixelBufferAccess> &dataPerSample, const tcu::ConstPixelBufferAccess &dataRS) const
539 {
540 if (checkForErrorMS(imageMSInfo, dataPerSample, 0))
541 return tcu::TestStatus::fail("Varying values are not sampled at gl_SamplePosition");
542
543 if (checkForErrorRS(imageRSInfo, dataRS, 0))
544 return tcu::TestStatus::fail("Varying values are not sampled at gl_SamplePosition");
545
546 return tcu::TestStatus::pass("Passed");
547 }
548
549 class MSCaseSamplePosCorrectness;
550
551 template <>
checkSupport(Context & context) const552 void MSCase<MSCaseSamplePosCorrectness>::checkSupport(Context &context) const
553 {
554 checkGraphicsPipelineLibrarySupport(context);
555 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SAMPLE_RATE_SHADING);
556 }
557
558 template <>
init(void)559 void MSCase<MSCaseSamplePosCorrectness>::init(void)
560 {
561 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying gl_SamplePosition correctness:\n"
562 << " 1) Varying values should be sampled at the sample position.\n"
563 << " => fract(position_screen) == gl_SamplePosition\n"
564 << tcu::TestLog::EndMessage;
565
566 MultisampleCaseBase::init();
567 }
568
569 template <>
initPrograms(vk::SourceCollections & programCollection) const570 void MSCase<MSCaseSamplePosCorrectness>::initPrograms(vk::SourceCollections &programCollection) const
571 {
572 MSCaseBaseResolveAndPerSampleFetch::initPrograms(programCollection);
573
574 // Create vertex shaders
575 std::ostringstream vs;
576
577 vs << "#version 440\n"
578 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
579 << "layout(location = 1) in vec2 vs_in_position_screen;\n"
580 << "\n"
581 << "layout(location = 0) sample out vec2 vs_out_position_screen;\n"
582 << "\n"
583 << "out gl_PerVertex {\n"
584 << " vec4 gl_Position;\n"
585 << "};\n"
586 << "void main (void)\n"
587 << "{\n"
588 << " gl_Position = vs_in_position_ndc;\n"
589 << " vs_out_position_screen = vs_in_position_screen;\n"
590 << "}\n";
591
592 programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
593
594 // Create fragment shader
595 std::ostringstream fs;
596
597 fs << "#version 440\n"
598 << "layout(location = 0) sample in vec2 fs_in_position_screen;\n"
599 << "\n"
600 << "layout(location = 0) out vec4 fs_out_color;\n"
601 << "\n"
602 << "void main (void)\n"
603 << "{\n"
604 << " const float threshold = 0.15625; // 4 subpixel bits. Assume 3 accurate bits + 0.03125 for other errors\n"
605 << " const ivec2 nearby_pixel = ivec2(floor(fs_in_position_screen));\n"
606 << " bool ok = false;\n"
607 << "\n"
608 << " // sample at edge + inaccuaries may cause us to round to any neighboring pixel\n"
609 << " // check all neighbors for any match\n"
610 << " for (int dy = -1; dy <= 1; ++dy)\n"
611 << " for (int dx = -1; dx <= 1; ++dx)\n"
612 << " {\n"
613 << " ivec2 current_pixel = nearby_pixel + ivec2(dx, dy);\n"
614 << " vec2 position_inside_pixel = vec2(current_pixel) + gl_SamplePosition;\n"
615 << " vec2 position_diff = abs(position_inside_pixel - fs_in_position_screen);\n"
616 << "\n"
617 << " if (all(lessThan(position_diff, vec2(threshold))))\n"
618 << " ok = true;\n"
619 << " }\n"
620 << "\n"
621 << " if (ok)\n"
622 << " fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
623 << " else\n"
624 << " fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
625 << "}\n";
626
627 programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
628 }
629
630 template <>
createInstance(Context & context) const631 TestInstance *MSCase<MSCaseSamplePosCorrectness>::createInstance(Context &context) const
632 {
633 return new MSInstance<MSInstanceSamplePosCorrectness>(context, m_imageMSParams);
634 }
635
636 class MSInstanceSampleMaskPattern : public MSInstanceBaseResolveAndPerSampleFetch
637 {
638 public:
639 MSInstanceSampleMaskPattern(Context &context, const ImageMSParams &imageMSParams);
640
641 VkPipelineMultisampleStateCreateInfo getMSStateCreateInfo(const ImageMSParams &imageMSParams) const;
642
643 const VkDescriptorSetLayout *createMSPassDescSetLayout(const ImageMSParams &imageMSParams);
644
645 const VkDescriptorSet *createMSPassDescSet(const ImageMSParams &imageMSParams,
646 const VkDescriptorSetLayout *descSetLayout);
647
648 VertexDataDesc getVertexDataDescripton(void) const;
649
650 void uploadVertexData(const Allocation &vertexBufferAllocation, const VertexDataDesc &vertexDataDescripton) const;
651
652 tcu::TestStatus verifyImageData(const vk::VkImageCreateInfo &imageMSInfo, const vk::VkImageCreateInfo &imageRSInfo,
653 const std::vector<tcu::ConstPixelBufferAccess> &dataPerSample,
654 const tcu::ConstPixelBufferAccess &dataRS) const;
655
656 protected:
657 VkSampleMask m_sampleMask;
658 Move<VkDescriptorSetLayout> m_descriptorSetLayout;
659 Move<VkDescriptorPool> m_descriptorPool;
660 Move<VkDescriptorSet> m_descriptorSet;
661 de::MovePtr<BufferWithMemory> m_buffer;
662 };
663
MSInstanceSampleMaskPattern(Context & context,const ImageMSParams & imageMSParams)664 MSInstanceSampleMaskPattern::MSInstanceSampleMaskPattern(Context &context, const ImageMSParams &imageMSParams)
665 : MSInstanceBaseResolveAndPerSampleFetch(context, imageMSParams)
666 {
667 m_sampleMask = 0xAAAAAAAAu & ((1u << imageMSParams.numSamples) - 1u);
668 }
669
getMSStateCreateInfo(const ImageMSParams & imageMSParams) const670 VkPipelineMultisampleStateCreateInfo MSInstanceSampleMaskPattern::getMSStateCreateInfo(
671 const ImageMSParams &imageMSParams) const
672 {
673 const VkPipelineMultisampleStateCreateInfo multisampleStateInfo = {
674 VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
675 DE_NULL, // const void* pNext;
676 (VkPipelineMultisampleStateCreateFlags)0u, // VkPipelineMultisampleStateCreateFlags flags;
677 imageMSParams.numSamples, // VkSampleCountFlagBits rasterizationSamples;
678 VK_FALSE, // VkBool32 sampleShadingEnable;
679 imageMSParams.shadingRate, // float minSampleShading;
680 &m_sampleMask, // const VkSampleMask* pSampleMask;
681 VK_FALSE, // VkBool32 alphaToCoverageEnable;
682 VK_FALSE, // VkBool32 alphaToOneEnable;
683 };
684
685 return multisampleStateInfo;
686 }
687
createMSPassDescSetLayout(const ImageMSParams & imageMSParams)688 const VkDescriptorSetLayout *MSInstanceSampleMaskPattern::createMSPassDescSetLayout(const ImageMSParams &imageMSParams)
689 {
690 DE_UNREF(imageMSParams);
691
692 const DeviceInterface &deviceInterface = m_context.getDeviceInterface();
693 const VkDevice device = m_context.getDevice();
694
695 // Create descriptor set layout
696 m_descriptorSetLayout = DescriptorSetLayoutBuilder()
697 .addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT)
698 .build(deviceInterface, device);
699
700 return &m_descriptorSetLayout.get();
701 }
702
createMSPassDescSet(const ImageMSParams & imageMSParams,const VkDescriptorSetLayout * descSetLayout)703 const VkDescriptorSet *MSInstanceSampleMaskPattern::createMSPassDescSet(const ImageMSParams &imageMSParams,
704 const VkDescriptorSetLayout *descSetLayout)
705 {
706 DE_UNREF(imageMSParams);
707
708 const DeviceInterface &deviceInterface = m_context.getDeviceInterface();
709 const VkDevice device = m_context.getDevice();
710 Allocator &allocator = m_context.getDefaultAllocator();
711
712 // Create descriptor pool
713 m_descriptorPool = DescriptorPoolBuilder()
714 .addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u)
715 .build(deviceInterface, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
716
717 // Create descriptor set
718 m_descriptorSet = makeDescriptorSet(deviceInterface, device, *m_descriptorPool, *descSetLayout);
719
720 const VkBufferCreateInfo bufferSampleMaskInfo =
721 makeBufferCreateInfo(sizeof(VkSampleMask), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
722
723 m_buffer = de::MovePtr<BufferWithMemory>(
724 new BufferWithMemory(deviceInterface, device, allocator, bufferSampleMaskInfo, MemoryRequirement::HostVisible));
725
726 deMemcpy(m_buffer->getAllocation().getHostPtr(), &m_sampleMask, sizeof(VkSampleMask));
727
728 flushAlloc(deviceInterface, device, m_buffer->getAllocation());
729
730 const VkDescriptorBufferInfo descBufferInfo = makeDescriptorBufferInfo(**m_buffer, 0u, sizeof(VkSampleMask));
731
732 DescriptorSetUpdateBuilder()
733 .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
734 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descBufferInfo)
735 .update(deviceInterface, device);
736
737 return &m_descriptorSet.get();
738 }
739
getVertexDataDescripton(void) const740 MultisampleInstanceBase::VertexDataDesc MSInstanceSampleMaskPattern::getVertexDataDescripton(void) const
741 {
742 return getVertexDataDescriptonNdc();
743 }
744
uploadVertexData(const Allocation & vertexBufferAllocation,const VertexDataDesc & vertexDataDescripton) const745 void MSInstanceSampleMaskPattern::uploadVertexData(const Allocation &vertexBufferAllocation,
746 const VertexDataDesc &vertexDataDescripton) const
747 {
748 uploadVertexDataNdc(vertexBufferAllocation, vertexDataDescripton);
749 }
750
verifyImageData(const vk::VkImageCreateInfo & imageMSInfo,const vk::VkImageCreateInfo & imageRSInfo,const std::vector<tcu::ConstPixelBufferAccess> & dataPerSample,const tcu::ConstPixelBufferAccess & dataRS) const751 tcu::TestStatus MSInstanceSampleMaskPattern::verifyImageData(
752 const vk::VkImageCreateInfo &imageMSInfo, const vk::VkImageCreateInfo &imageRSInfo,
753 const std::vector<tcu::ConstPixelBufferAccess> &dataPerSample, const tcu::ConstPixelBufferAccess &dataRS) const
754 {
755 DE_UNREF(imageRSInfo);
756 DE_UNREF(dataRS);
757
758 if (checkForErrorMS(imageMSInfo, dataPerSample, 0))
759 return tcu::TestStatus::fail("gl_SampleMaskIn bits have not been killed by pSampleMask state");
760
761 return tcu::TestStatus::pass("Passed");
762 }
763
764 class MSCaseSampleMaskPattern;
765
766 template <>
init(void)767 void MSCase<MSCaseSampleMaskPattern>::init(void)
768 {
769 m_testCtx.getLog() << tcu::TestLog::Message
770 << "Verifying gl_SampleMaskIn value with pSampleMask state. gl_SampleMaskIn does not contain "
771 "any bits set that are have been killed by pSampleMask state. Expecting:\n"
772 << "Expected result: gl_SampleMaskIn AND ~(pSampleMask) should be zero.\n"
773 << tcu::TestLog::EndMessage;
774
775 MultisampleCaseBase::init();
776 }
777
778 template <>
initPrograms(vk::SourceCollections & programCollection) const779 void MSCase<MSCaseSampleMaskPattern>::initPrograms(vk::SourceCollections &programCollection) const
780 {
781 MSCaseBaseResolveAndPerSampleFetch::initPrograms(programCollection);
782
783 // Create vertex shader
784 std::ostringstream vs;
785
786 vs << "#version 440\n"
787 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
788 << "\n"
789 << "out gl_PerVertex {\n"
790 << " vec4 gl_Position;\n"
791 << "};\n"
792 << "void main (void)\n"
793 << "{\n"
794 << " gl_Position = vs_in_position_ndc;\n"
795 << "}\n";
796
797 programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
798
799 // Create fragment shader
800 std::ostringstream fs;
801
802 fs << "#version 440\n"
803 << "\n"
804 << "layout(location = 0) out vec4 fs_out_color;\n"
805 << "\n"
806 << "layout(set = 0, binding = 0, std140) uniform SampleMaskBlock\n"
807 << "{\n"
808 << " int sampleMaskPattern;\n"
809 << "};"
810 << "\n"
811 << "void main (void)\n"
812 << "{\n"
813 << " if ((gl_SampleMaskIn[0] & ~sampleMaskPattern) != 0)\n"
814 << " fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
815 << " else\n"
816 << " fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
817 << "}\n";
818
819 programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
820 }
821
822 template <>
createInstance(Context & context) const823 TestInstance *MSCase<MSCaseSampleMaskPattern>::createInstance(Context &context) const
824 {
825 return new MSInstanceSampleMaskPattern(context, m_imageMSParams);
826 }
827
828 class MSInstanceSampleMaskBitCount;
829
830 template <>
getVertexDataDescripton(void) const831 MultisampleInstanceBase::VertexDataDesc MSInstance<MSInstanceSampleMaskBitCount>::getVertexDataDescripton(void) const
832 {
833 return getVertexDataDescriptonNdc();
834 }
835
836 template <>
uploadVertexData(const Allocation & vertexBufferAllocation,const VertexDataDesc & vertexDataDescripton) const837 void MSInstance<MSInstanceSampleMaskBitCount>::uploadVertexData(const Allocation &vertexBufferAllocation,
838 const VertexDataDesc &vertexDataDescripton) const
839 {
840 uploadVertexDataNdc(vertexBufferAllocation, vertexDataDescripton);
841 }
842
843 template <>
verifyImageData(const vk::VkImageCreateInfo & imageMSInfo,const vk::VkImageCreateInfo & imageRSInfo,const std::vector<tcu::ConstPixelBufferAccess> & dataPerSample,const tcu::ConstPixelBufferAccess & dataRS) const844 tcu::TestStatus MSInstance<MSInstanceSampleMaskBitCount>::verifyImageData(
845 const vk::VkImageCreateInfo &imageMSInfo, const vk::VkImageCreateInfo &imageRSInfo,
846 const std::vector<tcu::ConstPixelBufferAccess> &dataPerSample, const tcu::ConstPixelBufferAccess &dataRS) const
847 {
848 DE_UNREF(imageRSInfo);
849 DE_UNREF(dataRS);
850
851 if (checkForErrorMS(imageMSInfo, dataPerSample, 0))
852 return tcu::TestStatus::fail("gl_SampleMaskIn has an illegal number of bits for some shader invocations");
853
854 return tcu::TestStatus::pass("Passed");
855 }
856
857 class MSCaseSampleMaskBitCount;
858
859 template <>
checkSupport(Context & context) const860 void MSCase<MSCaseSampleMaskBitCount>::checkSupport(Context &context) const
861 {
862 checkGraphicsPipelineLibrarySupport(context);
863 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SAMPLE_RATE_SHADING);
864 }
865
866 template <>
init(void)867 void MSCase<MSCaseSampleMaskBitCount>::init(void)
868 {
869 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying gl_SampleMaskIn.\n"
870 << " Fragment shader will be invoked numSamples times.\n"
871 << " => gl_SampleMaskIn should have a number of bits that depends on the shading rate.\n"
872 << tcu::TestLog::EndMessage;
873
874 MultisampleCaseBase::init();
875 }
876
877 template <>
initPrograms(vk::SourceCollections & programCollection) const878 void MSCase<MSCaseSampleMaskBitCount>::initPrograms(vk::SourceCollections &programCollection) const
879 {
880 MSCaseBaseResolveAndPerSampleFetch::initPrograms(programCollection);
881
882 // Create vertex shader
883 std::ostringstream vs;
884
885 vs << "#version 440\n"
886 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
887 << "\n"
888 << "out gl_PerVertex {\n"
889 << " vec4 gl_Position;\n"
890 << "};\n"
891 << "void main (void)\n"
892 << "{\n"
893 << " gl_Position = vs_in_position_ndc;\n"
894 << "}\n";
895
896 programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
897
898 // Create fragment shader
899 std::ostringstream fs;
900
901 // The worst case scenario would be all invocations except one covering a single sample, and then one invocation covering the rest.
902 const int minInvocations =
903 static_cast<int>(std::ceil(static_cast<float>(m_imageMSParams.numSamples) * m_imageMSParams.shadingRate));
904 const int minCount = 1;
905 const int maxCount = m_imageMSParams.numSamples - (minInvocations - 1);
906
907 fs << "#version 440\n"
908 << "\n"
909 << "layout(location = 0) out vec4 fs_out_color;\n"
910 << "\n"
911 << "void main (void)\n"
912 << "{\n"
913 << " const int maskBitCount = bitCount(gl_SampleMaskIn[0]);\n"
914 << "\n"
915 << " if (maskBitCount < " << minCount << " || maskBitCount > " << maxCount << ")\n"
916 << " fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
917 << " else\n"
918 << " fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
919 << "}\n";
920
921 programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
922 }
923
924 template <>
createInstance(Context & context) const925 TestInstance *MSCase<MSCaseSampleMaskBitCount>::createInstance(Context &context) const
926 {
927 return new MSInstance<MSInstanceSampleMaskBitCount>(context, m_imageMSParams);
928 }
929
930 class MSInstanceSampleMaskCorrectBit;
931
932 template <>
getVertexDataDescripton(void) const933 MultisampleInstanceBase::VertexDataDesc MSInstance<MSInstanceSampleMaskCorrectBit>::getVertexDataDescripton(void) const
934 {
935 return getVertexDataDescriptonNdc();
936 }
937
938 template <>
uploadVertexData(const Allocation & vertexBufferAllocation,const VertexDataDesc & vertexDataDescripton) const939 void MSInstance<MSInstanceSampleMaskCorrectBit>::uploadVertexData(const Allocation &vertexBufferAllocation,
940 const VertexDataDesc &vertexDataDescripton) const
941 {
942 uploadVertexDataNdc(vertexBufferAllocation, vertexDataDescripton);
943 }
944
945 template <>
verifyImageData(const vk::VkImageCreateInfo & imageMSInfo,const vk::VkImageCreateInfo & imageRSInfo,const std::vector<tcu::ConstPixelBufferAccess> & dataPerSample,const tcu::ConstPixelBufferAccess & dataRS) const946 tcu::TestStatus MSInstance<MSInstanceSampleMaskCorrectBit>::verifyImageData(
947 const vk::VkImageCreateInfo &imageMSInfo, const vk::VkImageCreateInfo &imageRSInfo,
948 const std::vector<tcu::ConstPixelBufferAccess> &dataPerSample, const tcu::ConstPixelBufferAccess &dataRS) const
949 {
950 DE_UNREF(imageRSInfo);
951 DE_UNREF(dataRS);
952
953 if (checkForErrorMS(imageMSInfo, dataPerSample, 0))
954 return tcu::TestStatus::fail("The bit corresponsing to current gl_SampleID is not set in gl_SampleMaskIn");
955
956 return tcu::TestStatus::pass("Passed");
957 }
958
959 class MSCaseSampleMaskCorrectBit;
960
961 template <>
checkSupport(Context & context) const962 void MSCase<MSCaseSampleMaskCorrectBit>::checkSupport(Context &context) const
963 {
964 checkGraphicsPipelineLibrarySupport(context);
965 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SAMPLE_RATE_SHADING);
966 }
967
968 template <>
init(void)969 void MSCase<MSCaseSampleMaskCorrectBit>::init(void)
970 {
971 m_testCtx.getLog()
972 << tcu::TestLog::Message << "Verifying gl_SampleMaskIn.\n"
973 << " Fragment shader will be invoked numSamples times.\n"
974 << " => In each invocation gl_SampleMaskIn should have the bit set that corresponds to gl_SampleID.\n"
975 << tcu::TestLog::EndMessage;
976
977 MultisampleCaseBase::init();
978 }
979
980 template <>
initPrograms(vk::SourceCollections & programCollection) const981 void MSCase<MSCaseSampleMaskCorrectBit>::initPrograms(vk::SourceCollections &programCollection) const
982 {
983 MSCaseBaseResolveAndPerSampleFetch::initPrograms(programCollection);
984
985 // Create vertex shader
986 std::ostringstream vs;
987
988 vs << "#version 440\n"
989 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
990 << "\n"
991 << "out gl_PerVertex {\n"
992 << " vec4 gl_Position;\n"
993 << "};\n"
994 << "void main (void)\n"
995 << "{\n"
996 << " gl_Position = vs_in_position_ndc;\n"
997 << "}\n";
998
999 programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
1000
1001 // Create fragment shader
1002 std::ostringstream fs;
1003
1004 fs << "#version 440\n"
1005 << "\n"
1006 << "layout(location = 0) out vec4 fs_out_color;\n"
1007 << "\n"
1008 << "void main (void)\n"
1009 << "{\n"
1010 << " if (((gl_SampleMaskIn[0] >> gl_SampleID) & 0x01) == 0x01)\n"
1011 << " fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
1012 << " else\n"
1013 << " fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
1014 << "}\n";
1015
1016 programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
1017 }
1018
1019 template <>
createInstance(Context & context) const1020 TestInstance *MSCase<MSCaseSampleMaskCorrectBit>::createInstance(Context &context) const
1021 {
1022 return new MSInstance<MSInstanceSampleMaskCorrectBit>(context, m_imageMSParams);
1023 }
1024
1025 class MSInstanceSampleMaskWrite;
1026
1027 template <>
getVertexDataDescripton(void) const1028 MultisampleInstanceBase::VertexDataDesc MSInstance<MSInstanceSampleMaskWrite>::getVertexDataDescripton(void) const
1029 {
1030 return getVertexDataDescriptonNdc();
1031 }
1032
1033 template <>
uploadVertexData(const Allocation & vertexBufferAllocation,const VertexDataDesc & vertexDataDescripton) const1034 void MSInstance<MSInstanceSampleMaskWrite>::uploadVertexData(const Allocation &vertexBufferAllocation,
1035 const VertexDataDesc &vertexDataDescripton) const
1036 {
1037 uploadVertexDataNdc(vertexBufferAllocation, vertexDataDescripton);
1038 }
1039
1040 //! Creates VkPipelineMultisampleStateCreateInfo with sample shading disabled.
1041 template <>
getMSStateCreateInfo(const ImageMSParams & imageMSParams) const1042 VkPipelineMultisampleStateCreateInfo MSInstance<MSInstanceSampleMaskWrite>::getMSStateCreateInfo(
1043 const ImageMSParams &imageMSParams) const
1044 {
1045 const VkPipelineMultisampleStateCreateInfo multisampleStateInfo = {
1046 VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
1047 DE_NULL, // const void* pNext;
1048 (VkPipelineMultisampleStateCreateFlags)0u, // VkPipelineMultisampleStateCreateFlags flags;
1049 imageMSParams.numSamples, // VkSampleCountFlagBits rasterizationSamples;
1050 VK_FALSE, // VkBool32 sampleShadingEnable;
1051 imageMSParams.shadingRate, // float minSampleShading;
1052 DE_NULL, // const VkSampleMask* pSampleMask;
1053 VK_FALSE, // VkBool32 alphaToCoverageEnable;
1054 VK_FALSE, // VkBool32 alphaToOneEnable;
1055 };
1056
1057 return multisampleStateInfo;
1058 }
1059
1060 template <>
verifyImageData(const vk::VkImageCreateInfo & imageMSInfo,const vk::VkImageCreateInfo & imageRSInfo,const std::vector<tcu::ConstPixelBufferAccess> & dataPerSample,const tcu::ConstPixelBufferAccess & dataRS) const1061 tcu::TestStatus MSInstance<MSInstanceSampleMaskWrite>::verifyImageData(
1062 const vk::VkImageCreateInfo &imageMSInfo, const vk::VkImageCreateInfo &imageRSInfo,
1063 const std::vector<tcu::ConstPixelBufferAccess> &dataPerSample, const tcu::ConstPixelBufferAccess &dataRS) const
1064 {
1065 const uint32_t numSamples = static_cast<uint32_t>(imageMSInfo.samples);
1066
1067 for (uint32_t z = 0u; z < imageMSInfo.extent.depth; ++z)
1068 for (uint32_t y = 0u; y < imageMSInfo.extent.height; ++y)
1069 for (uint32_t x = 0u; x < imageMSInfo.extent.width; ++x)
1070 {
1071 for (uint32_t sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
1072 {
1073 const uint32_t firstComponent = dataPerSample[sampleNdx].getPixelUint(x, y, z)[0];
1074
1075 if (firstComponent != 0u && firstComponent != 255u)
1076 return tcu::TestStatus::fail("Expected color to be zero or saturated on the first channel");
1077 }
1078 }
1079
1080 for (uint32_t z = 0u; z < imageRSInfo.extent.depth; ++z)
1081 for (uint32_t y = 0u; y < imageRSInfo.extent.height; ++y)
1082 for (uint32_t x = 0u; x < imageRSInfo.extent.width; ++x)
1083 {
1084 const float firstComponent = dataRS.getPixel(x, y, z)[0];
1085
1086 if (deFloatAbs(firstComponent - 0.5f) > 0.02f)
1087 return tcu::TestStatus::fail("Expected resolve color to be half intensity on the first channel");
1088 }
1089
1090 return tcu::TestStatus::pass("Passed");
1091 }
1092
1093 class MSCaseSampleMaskWrite;
1094
1095 template <>
init(void)1096 void MSCase<MSCaseSampleMaskWrite>::init(void)
1097 {
1098 m_testCtx.getLog() << tcu::TestLog::Message << "Discarding half of the samples using gl_SampleMask."
1099 << "Expecting half intensity on multisample targets (numSamples > 1)\n"
1100 << tcu::TestLog::EndMessage;
1101
1102 MultisampleCaseBase::init();
1103 }
1104
1105 template <>
initPrograms(vk::SourceCollections & programCollection) const1106 void MSCase<MSCaseSampleMaskWrite>::initPrograms(vk::SourceCollections &programCollection) const
1107 {
1108 MSCaseBaseResolveAndPerSampleFetch::initPrograms(programCollection);
1109
1110 // Create vertex shader
1111 std::ostringstream vs;
1112
1113 vs << "#version 440\n"
1114 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
1115 << "\n"
1116 << "out gl_PerVertex {\n"
1117 << " vec4 gl_Position;\n"
1118 << "};\n"
1119 << "void main (void)\n"
1120 << "{\n"
1121 << " gl_Position = vs_in_position_ndc;\n"
1122 << "}\n";
1123
1124 programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
1125
1126 // Create fragment shader
1127 std::ostringstream fs;
1128
1129 fs << "#version 440\n"
1130 << "\n"
1131 << "layout(location = 0) out vec4 fs_out_color;\n"
1132 << "\n"
1133 << "void main (void)\n"
1134 << "{\n"
1135 << " gl_SampleMask[0] = 0xAAAAAAAA;\n"
1136 << "\n"
1137 << " fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
1138 << "}\n";
1139
1140 programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
1141 }
1142
1143 template <>
createInstance(Context & context) const1144 TestInstance *MSCase<MSCaseSampleMaskWrite>::createInstance(Context &context) const
1145 {
1146 return new MSInstance<MSInstanceSampleMaskWrite>(context, m_imageMSParams);
1147 }
1148
1149 const set<uint32_t> kValidSquareSampleCounts = {
1150 vk::VK_SAMPLE_COUNT_1_BIT, vk::VK_SAMPLE_COUNT_2_BIT, vk::VK_SAMPLE_COUNT_4_BIT,
1151 vk::VK_SAMPLE_COUNT_8_BIT, vk::VK_SAMPLE_COUNT_16_BIT,
1152 };
1153
assertSquareSampleCount(uint32_t sampleCount)1154 void assertSquareSampleCount(uint32_t sampleCount)
1155 {
1156 DE_ASSERT(kValidSquareSampleCounts.find(sampleCount) != kValidSquareSampleCounts.end());
1157 DE_UNREF(sampleCount); // for release builds.
1158 }
1159
1160 // When dealing with N samples, each coordinate (x, y) will be used to decide which samples will be written to, using N/2 bits for
1161 // each of the X and Y values. Take into account this returns 0 for 1 sample.
bitsPerCoord(uint32_t numSamples)1162 uint32_t bitsPerCoord(uint32_t numSamples)
1163 {
1164 assertSquareSampleCount(numSamples);
1165 return (numSamples / 2u);
1166 }
1167
1168 // These tests will try to verify all write or mask bit combinations for the given sample count, and will verify one combination per
1169 // image pixel. This means the following image sizes need to be used:
1170 // - 2 samples: 2x2
1171 // - 4 samples: 4x4
1172 // - 8 samples: 16x16
1173 // - 16 samples: 256x256
1174 // In other words, images will be square with 2^(samples-1) pixels on each side.
imageSize(uint32_t sampleCount)1175 vk::VkExtent2D imageSize(uint32_t sampleCount)
1176 {
1177 assertSquareSampleCount(sampleCount);
1178
1179 // Special case: 2x1 image (not actually square).
1180 if (sampleCount == vk::VK_SAMPLE_COUNT_1_BIT)
1181 return vk::VkExtent2D{2u, 1u};
1182
1183 // Other cases: square image as described above.
1184 const auto dim = (1u << (sampleCount >> 1u));
1185 return vk::VkExtent2D{dim, dim};
1186 }
1187
getExtent3D(uint32_t sampleCount)1188 vk::VkExtent3D getExtent3D(uint32_t sampleCount)
1189 {
1190 const auto size = imageSize(sampleCount);
1191 return vk::VkExtent3D{size.width, size.height, 1u};
1192 }
1193
getShaderDecl(const tcu::Vec4 & color)1194 std::string getShaderDecl(const tcu::Vec4 &color)
1195 {
1196 std::ostringstream declaration;
1197 declaration << "vec4(" << color.x() << ", " << color.y() << ", " << color.z() << ", " << color.w() << ")";
1198 return declaration.str();
1199 }
1200
1201 struct WriteSampleParams
1202 {
1203 vk::PipelineConstructionType pipelineConstructionType;
1204 vk::VkSampleCountFlagBits sampleCount;
1205 };
1206
1207 class WriteSampleTest : public vkt::TestCase
1208 {
1209 public:
WriteSampleTest(tcu::TestContext & testCtx,const std::string & name,const WriteSampleParams & params)1210 WriteSampleTest(tcu::TestContext &testCtx, const std::string &name, const WriteSampleParams ¶ms)
1211 : vkt::TestCase(testCtx, name)
1212 , m_params(params)
1213 {
1214 }
~WriteSampleTest(void)1215 virtual ~WriteSampleTest(void)
1216 {
1217 }
1218
1219 virtual void initPrograms(vk::SourceCollections &programCollection) const;
1220 virtual vkt::TestInstance *createInstance(Context &context) const;
1221 virtual void checkSupport(Context &context) const;
1222
1223 static const tcu::Vec4 kClearColor;
1224 static const tcu::Vec4 kBadColor;
1225 static const tcu::Vec4 kGoodColor;
1226 static const tcu::Vec4 kWriteColor;
1227
1228 static constexpr vk::VkFormat kImageFormat = vk::VK_FORMAT_R8G8B8A8_UNORM;
1229
1230 // Keep these two in sync.
1231 static constexpr vk::VkImageUsageFlags kUsageFlags =
1232 (vk::VK_IMAGE_USAGE_STORAGE_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT | vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT);
1233 static constexpr vk::VkFormatFeatureFlags kFeatureFlags =
1234 (vk::VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT | vk::VK_FORMAT_FEATURE_TRANSFER_SRC_BIT |
1235 vk::VK_FORMAT_FEATURE_TRANSFER_DST_BIT);
1236
1237 private:
1238 WriteSampleParams m_params;
1239 };
1240
1241 const tcu::Vec4 WriteSampleTest::kClearColor{0.0f, 0.0f, 0.0f, 1.0f};
1242 const tcu::Vec4 WriteSampleTest::kBadColor{1.0f, 0.0f, 0.0f, 1.0f};
1243 const tcu::Vec4 WriteSampleTest::kGoodColor{0.0f, 1.0f, 0.0f, 1.0f};
1244 const tcu::Vec4 WriteSampleTest::kWriteColor{0.0f, 0.0f, 1.0f, 1.0f};
1245
1246 class WriteSampleTestInstance : public vkt::TestInstance
1247 {
1248 public:
WriteSampleTestInstance(vkt::Context & context,const WriteSampleParams & params)1249 WriteSampleTestInstance(vkt::Context &context, const WriteSampleParams ¶ms)
1250 : vkt::TestInstance(context)
1251 , m_params(params)
1252 {
1253 }
1254
~WriteSampleTestInstance(void)1255 virtual ~WriteSampleTestInstance(void)
1256 {
1257 }
1258
1259 virtual tcu::TestStatus iterate(void);
1260
1261 private:
1262 WriteSampleParams m_params;
1263 };
1264
checkSupport(Context & context) const1265 void WriteSampleTest::checkSupport(Context &context) const
1266 {
1267 const auto &vki = context.getInstanceInterface();
1268 const auto physicalDevice = context.getPhysicalDevice();
1269
1270 // Check multisample storage images support.
1271 const auto features = vk::getPhysicalDeviceFeatures(vki, physicalDevice);
1272 if (!features.shaderStorageImageMultisample)
1273 TCU_THROW(NotSupportedError, "Using multisample images as storage is not supported");
1274
1275 // Check the specific image format.
1276 const auto properties = vk::getPhysicalDeviceFormatProperties(vki, physicalDevice, kImageFormat);
1277 if (!(properties.optimalTilingFeatures & kFeatureFlags))
1278 TCU_THROW(NotSupportedError, "Format does not support the required features");
1279
1280 // Check the supported sample count.
1281 const auto imgProps = vk::getPhysicalDeviceImageFormatProperties(
1282 vki, physicalDevice, kImageFormat, vk::VK_IMAGE_TYPE_2D, vk::VK_IMAGE_TILING_OPTIMAL, kUsageFlags, 0u);
1283 if (!(imgProps.sampleCounts & m_params.sampleCount))
1284 TCU_THROW(NotSupportedError, "Format does not support the required sample count");
1285
1286 checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
1287 m_params.pipelineConstructionType);
1288 }
1289
initPrograms(vk::SourceCollections & programCollection) const1290 void WriteSampleTest::initPrograms(vk::SourceCollections &programCollection) const
1291 {
1292 std::ostringstream writeColorDecl, goodColorDecl, badColorDecl, clearColorDecl, allColorDecl;
1293
1294 writeColorDecl << " vec4 wcolor = " << getShaderDecl(kWriteColor) << ";\n";
1295 goodColorDecl << " vec4 bcolor = " << getShaderDecl(kBadColor) << ";\n";
1296 badColorDecl << " vec4 gcolor = " << getShaderDecl(kGoodColor) << ";\n";
1297 clearColorDecl << " vec4 ccolor = " << getShaderDecl(kClearColor) << ";\n";
1298 allColorDecl << writeColorDecl.str() << goodColorDecl.str() << badColorDecl.str() << clearColorDecl.str();
1299
1300 std::ostringstream shaderWrite;
1301
1302 const auto bpc = de::toString(bitsPerCoord(m_params.sampleCount));
1303 const auto count = de::toString(m_params.sampleCount);
1304
1305 shaderWrite << "#version 450\n"
1306 << "\n"
1307 << "layout (rgba8, set=0, binding=0) uniform image2DMS writeImg;\n"
1308 << "layout (rgba8, set=0, binding=1) uniform image2D verificationImg;\n"
1309 << "\n"
1310 << "void main()\n"
1311 << "{\n"
1312 << writeColorDecl.str() << " uvec2 ucoords = uvec2(gl_GlobalInvocationID.xy);\n"
1313 << " ivec2 icoords = ivec2(ucoords);\n"
1314 << " uint writeMask = ((ucoords.x << " << bpc << ") | ucoords.y);\n"
1315 << " for (uint i = 0; i < " << count << "; ++i)\n"
1316 << " {\n"
1317 << " if ((writeMask & (1 << i)) != 0)\n"
1318 << " imageStore(writeImg, icoords, int(i), wcolor);\n"
1319 << " }\n"
1320 << "}\n";
1321
1322 std::ostringstream shaderVerify;
1323
1324 shaderVerify << "#version 450\n"
1325 << "\n"
1326 << "layout (rgba8, set=0, binding=0) uniform image2DMS writeImg;\n"
1327 << "layout (rgba8, set=0, binding=1) uniform image2D verificationImg;\n"
1328 << "\n"
1329 << "void main()\n"
1330 << "{\n"
1331 << allColorDecl.str() << " uvec2 ucoords = uvec2(gl_GlobalInvocationID.xy);\n"
1332 << " ivec2 icoords = ivec2(ucoords);\n"
1333 << " uint writeMask = ((ucoords.x << " << bpc << ") | ucoords.y);\n"
1334 << " bool ok = true;\n"
1335 << " for (uint i = 0; i < " << count << "; ++i)\n"
1336 << " {\n"
1337 << " bool expectWrite = ((writeMask & (1 << i)) != 0);\n"
1338 << " vec4 sampleColor = imageLoad(writeImg, icoords, int(i));\n"
1339 << " vec4 wantedColor = (expectWrite ? wcolor : ccolor);\n"
1340 << " ok = ok && (sampleColor == wantedColor);\n"
1341 << " }\n"
1342 << " vec4 resultColor = (ok ? gcolor : bcolor);\n"
1343 << " imageStore(verificationImg, icoords, resultColor);\n"
1344 << "}\n";
1345
1346 programCollection.glslSources.add("write") << glu::ComputeSource(shaderWrite.str());
1347 programCollection.glslSources.add("verify") << glu::ComputeSource(shaderVerify.str());
1348 }
1349
createInstance(Context & context) const1350 vkt::TestInstance *WriteSampleTest::createInstance(Context &context) const
1351 {
1352 return new WriteSampleTestInstance{context, m_params};
1353 }
1354
iterate(void)1355 tcu::TestStatus WriteSampleTestInstance::iterate(void)
1356 {
1357 const auto &vkd = m_context.getDeviceInterface();
1358 const auto device = m_context.getDevice();
1359 auto &allocator = m_context.getDefaultAllocator();
1360 const auto queue = m_context.getUniversalQueue();
1361 const auto queueIndex = m_context.getUniversalQueueFamilyIndex();
1362 const auto extent3D = getExtent3D(m_params.sampleCount);
1363
1364 // Create storage image and verification image.
1365 const vk::VkImageCreateInfo storageImageInfo = {
1366 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
1367 nullptr, // const void* pNext;
1368 0u, // VkImageCreateFlags flags;
1369 vk::VK_IMAGE_TYPE_2D, // VkImageType imageType;
1370 WriteSampleTest::kImageFormat, // VkFormat format;
1371 extent3D, // VkExtent3D extent;
1372 1u, // uint32_t mipLevels;
1373 1u, // uint32_t arrayLayers;
1374 m_params.sampleCount, // VkSampleCountFlagBits samples;
1375 vk::VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
1376 WriteSampleTest::kUsageFlags, // VkImageUsageFlags usage;
1377 vk::VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1378 1u, // uint32_t queueFamilyIndexCount;
1379 &queueIndex, // const uint32_t* pQueueFamilyIndices;
1380 vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
1381 };
1382
1383 const vk::VkImageCreateInfo verificationImageInfo = {
1384 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
1385 nullptr, // const void* pNext;
1386 0u, // VkImageCreateFlags flags;
1387 vk::VK_IMAGE_TYPE_2D, // VkImageType imageType;
1388 WriteSampleTest::kImageFormat, // VkFormat format;
1389 extent3D, // VkExtent3D extent;
1390 1u, // uint32_t mipLevels;
1391 1u, // uint32_t arrayLayers;
1392 vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
1393 vk::VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
1394 WriteSampleTest::kUsageFlags, // VkImageUsageFlags usage;
1395 vk::VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1396 1u, // uint32_t queueFamilyIndexCount;
1397 &queueIndex, // const uint32_t* pQueueFamilyIndices;
1398 vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
1399 };
1400
1401 vk::ImageWithMemory storageImgPrt{vkd, device, allocator, storageImageInfo, vk::MemoryRequirement::Any};
1402 vk::ImageWithMemory verificationImgPtr{vkd, device, allocator, verificationImageInfo, vk::MemoryRequirement::Any};
1403
1404 const vk::VkImageSubresourceRange kSubresourceRange = {
1405 vk::VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
1406 0u, // uint32_t baseMipLevel;
1407 1u, // uint32_t levelCount;
1408 0u, // uint32_t baseArrayLayer;
1409 1u, // uint32_t layerCount;
1410 };
1411
1412 auto storageImgViewPtr = vk::makeImageView(vkd, device, storageImgPrt.get(), vk::VK_IMAGE_VIEW_TYPE_2D,
1413 WriteSampleTest::kImageFormat, kSubresourceRange);
1414 auto verificationImgViewPtr = vk::makeImageView(vkd, device, verificationImgPtr.get(), vk::VK_IMAGE_VIEW_TYPE_2D,
1415 WriteSampleTest::kImageFormat, kSubresourceRange);
1416
1417 // Prepare a staging buffer to check verification image.
1418 const auto tcuFormat = vk::mapVkFormat(WriteSampleTest::kImageFormat);
1419 const VkDeviceSize bufferSize = extent3D.width * extent3D.height * extent3D.depth * tcu::getPixelSize(tcuFormat);
1420 const auto stagingBufferInfo = vk::makeBufferCreateInfo(bufferSize, vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT);
1421 vk::BufferWithMemory stagingBuffer{vkd, device, allocator, stagingBufferInfo, MemoryRequirement::HostVisible};
1422
1423 // Descriptor set layout.
1424 vk::DescriptorSetLayoutBuilder layoutBuilder;
1425 layoutBuilder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, vk::VK_SHADER_STAGE_COMPUTE_BIT);
1426 layoutBuilder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, vk::VK_SHADER_STAGE_COMPUTE_BIT);
1427 auto descriptorSetLayout = layoutBuilder.build(vkd, device);
1428
1429 // Descriptor pool.
1430 vk::DescriptorPoolBuilder poolBuilder;
1431 poolBuilder.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 2u);
1432 auto descriptorPool = poolBuilder.build(vkd, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1433
1434 // Descriptor set.
1435 const auto descriptorSet = vk::makeDescriptorSet(vkd, device, descriptorPool.get(), descriptorSetLayout.get());
1436
1437 // Update descriptor set using the images.
1438 const auto storageImgDescriptorInfo =
1439 vk::makeDescriptorImageInfo(DE_NULL, storageImgViewPtr.get(), vk::VK_IMAGE_LAYOUT_GENERAL);
1440 const auto verificationImgDescriptorInfo =
1441 vk::makeDescriptorImageInfo(DE_NULL, verificationImgViewPtr.get(), vk::VK_IMAGE_LAYOUT_GENERAL);
1442
1443 vk::DescriptorSetUpdateBuilder updateBuilder;
1444 updateBuilder.writeSingle(descriptorSet.get(), vk::DescriptorSetUpdateBuilder::Location::binding(0u),
1445 vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &storageImgDescriptorInfo);
1446 updateBuilder.writeSingle(descriptorSet.get(), vk::DescriptorSetUpdateBuilder::Location::binding(1u),
1447 vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &verificationImgDescriptorInfo);
1448 updateBuilder.update(vkd, device);
1449
1450 // Create write and verification compute pipelines.
1451 auto shaderWriteModule = ShaderWrapper(vkd, device, m_context.getBinaryCollection().get("write"), 0u);
1452 auto shaderVerifyModule = ShaderWrapper(vkd, device, m_context.getBinaryCollection().get("verify"), 0u);
1453 auto pipelineLayout = vk::makePipelineLayout(vkd, device, descriptorSetLayout.get());
1454
1455 const vk::VkComputePipelineCreateInfo writePipelineCreateInfo = {
1456 vk::VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
1457 nullptr,
1458 0u, // flags
1459 {
1460 // compute shader
1461 vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
1462 nullptr, // const void* pNext;
1463 0u, // VkPipelineShaderStageCreateFlags flags;
1464 vk::VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlagBits stage;
1465 shaderWriteModule.getModule(), // VkShaderModule module;
1466 "main", // const char* pName;
1467 nullptr, // const VkSpecializationInfo* pSpecializationInfo;
1468 },
1469 pipelineLayout.get(), // layout
1470 DE_NULL, // basePipelineHandle
1471 0, // basePipelineIndex
1472 };
1473
1474 auto verificationPipelineCreateInfo = writePipelineCreateInfo;
1475 verificationPipelineCreateInfo.stage.module = shaderVerifyModule.getModule();
1476
1477 auto writePipeline = vk::createComputePipeline(vkd, device, DE_NULL, &writePipelineCreateInfo);
1478 auto verificationPipeline = vk::createComputePipeline(vkd, device, DE_NULL, &verificationPipelineCreateInfo);
1479
1480 // Transition images to the correct layout and buffers at different stages.
1481 auto storageImgPreClearBarrier =
1482 vk::makeImageMemoryBarrier(0, vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_IMAGE_LAYOUT_UNDEFINED,
1483 vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, storageImgPrt.get(), kSubresourceRange);
1484 auto storageImgPreShaderBarrier = vk::makeImageMemoryBarrier(
1485 vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_ACCESS_SHADER_WRITE_BIT, vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1486 vk::VK_IMAGE_LAYOUT_GENERAL, storageImgPrt.get(), kSubresourceRange);
1487 auto verificationImgPreShaderBarrier =
1488 vk::makeImageMemoryBarrier(0, vk::VK_ACCESS_SHADER_WRITE_BIT, vk::VK_IMAGE_LAYOUT_UNDEFINED,
1489 vk::VK_IMAGE_LAYOUT_GENERAL, verificationImgPtr.get(), kSubresourceRange);
1490 auto storageImgPreVerificationBarrier = vk::makeImageMemoryBarrier(
1491 vk::VK_ACCESS_SHADER_WRITE_BIT, vk::VK_ACCESS_SHADER_READ_BIT, vk::VK_IMAGE_LAYOUT_GENERAL,
1492 vk::VK_IMAGE_LAYOUT_GENERAL, storageImgPrt.get(), kSubresourceRange);
1493 auto verificationImgPostBarrier = vk::makeImageMemoryBarrier(
1494 vk::VK_ACCESS_SHADER_WRITE_BIT, vk::VK_ACCESS_TRANSFER_READ_BIT, vk::VK_IMAGE_LAYOUT_GENERAL,
1495 vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, verificationImgPtr.get(), kSubresourceRange);
1496 auto bufferBarrier = vk::makeBufferMemoryBarrier(vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_ACCESS_HOST_READ_BIT,
1497 stagingBuffer.get(), 0ull, bufferSize);
1498
1499 // Command buffer.
1500 auto cmdPool = vk::makeCommandPool(vkd, device, queueIndex);
1501 auto cmdBufferPtr = vk::allocateCommandBuffer(vkd, device, cmdPool.get(), vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1502 auto cmdBuffer = cmdBufferPtr.get();
1503
1504 // Clear color for the storage image.
1505 const auto clearColor = vk::makeClearValueColor(WriteSampleTest::kClearColor);
1506
1507 const vk::VkBufferImageCopy copyRegion = {
1508 0ull, // VkDeviceSize bufferOffset;
1509 extent3D.width, // uint32_t bufferRowLength;
1510 extent3D.height, // uint32_t bufferImageHeight;
1511 {
1512 // VkImageSubresourceLayers imageSubresource;
1513 vk::VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
1514 0u, // uint32_t mipLevel;
1515 0u, // uint32_t baseArrayLayer;
1516 1u, // uint32_t layerCount;
1517 },
1518 {0, 0, 0}, // VkOffset3D imageOffset;
1519 extent3D, // VkExtent3D imageExtent;
1520 };
1521
1522 // Record and submit commands.
1523 vk::beginCommandBuffer(vkd, cmdBuffer);
1524 // Clear storage image.
1525 vkd.cmdPipelineBarrier(cmdBuffer, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u,
1526 nullptr, 0u, nullptr, 1u, &storageImgPreClearBarrier);
1527 vkd.cmdClearColorImage(cmdBuffer, storageImgPrt.get(), vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColor.color,
1528 1u, &kSubresourceRange);
1529
1530 // Bind write pipeline and descriptor set.
1531 vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, writePipeline.get());
1532 vkd.cmdBindDescriptorSets(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout.get(), 0, 1u,
1533 &descriptorSet.get(), 0u, nullptr);
1534
1535 // Transition images to the appropriate layout before running the shader.
1536 vkd.cmdPipelineBarrier(cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0u,
1537 0u, nullptr, 0u, nullptr, 1u, &storageImgPreShaderBarrier);
1538 vkd.cmdPipelineBarrier(cmdBuffer, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
1539 0u, 0u, nullptr, 0u, nullptr, 1u, &verificationImgPreShaderBarrier);
1540
1541 // Run shader.
1542 vkd.cmdDispatch(cmdBuffer, extent3D.width, extent3D.height, extent3D.depth);
1543
1544 // Bind verification pipeline.
1545 vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, verificationPipeline.get());
1546
1547 // Make sure writes happen before reads in the second dispatch for the storage image.
1548 vkd.cmdPipelineBarrier(cmdBuffer, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
1549 vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u,
1550 &storageImgPreVerificationBarrier);
1551
1552 // Run verification shader.
1553 vkd.cmdDispatch(cmdBuffer, extent3D.width, extent3D.height, extent3D.depth);
1554
1555 // Change verification image layout to prepare the transfer.
1556 vkd.cmdPipelineBarrier(cmdBuffer, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
1557 0u, nullptr, 0u, nullptr, 1u, &verificationImgPostBarrier);
1558
1559 // Copy verification image to staging buffer.
1560 vkd.cmdCopyImageToBuffer(cmdBuffer, verificationImgPtr.get(), vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1561 stagingBuffer.get(), 1u, ©Region);
1562 vkd.cmdPipelineBarrier(cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_PIPELINE_STAGE_HOST_BIT, 0, 0u,
1563 nullptr, 1u, &bufferBarrier, 0u, nullptr);
1564
1565 vk::endCommandBuffer(vkd, cmdBuffer);
1566
1567 // Run shaders.
1568 vk::submitCommandsAndWait(vkd, device, queue, cmdBuffer);
1569
1570 // Read buffer pixels.
1571 const auto &bufferAlloc = stagingBuffer.getAllocation();
1572 vk::invalidateAlloc(vkd, device, bufferAlloc);
1573
1574 // Copy buffer data to texture level and verify all pixels have the proper color.
1575 tcu::TextureLevel texture{tcuFormat, static_cast<int>(extent3D.width), static_cast<int>(extent3D.height),
1576 static_cast<int>(extent3D.depth)};
1577 const auto access = texture.getAccess();
1578 deMemcpy(access.getDataPtr(), reinterpret_cast<char *>(bufferAlloc.getHostPtr()) + bufferAlloc.getOffset(),
1579 static_cast<size_t>(bufferSize));
1580
1581 for (int i = 0; i < access.getWidth(); ++i)
1582 for (int j = 0; j < access.getHeight(); ++j)
1583 for (int k = 0; k < access.getDepth(); ++k)
1584 {
1585 if (access.getPixel(i, j, k) != WriteSampleTest::kGoodColor)
1586 {
1587 std::ostringstream msg;
1588 msg << "Invalid result at pixel (" << i << ", " << j << ", " << k
1589 << "); check error mask for more details";
1590 m_context.getTestContext().getLog()
1591 << tcu::TestLog::Image("ErrorMask", "Indicates which pixels have unexpected values", access);
1592 return tcu::TestStatus::fail(msg.str());
1593 }
1594 }
1595
1596 return tcu::TestStatus::pass("Pass");
1597 }
1598
1599 using WriteSampleMaskParams = WriteSampleParams;
1600
1601 class WriteSampleMaskTestCase : public vkt::TestCase
1602 {
1603 public:
1604 WriteSampleMaskTestCase(tcu::TestContext &testCtx, const std::string &name, const WriteSampleMaskParams ¶ms);
~WriteSampleMaskTestCase(void)1605 virtual ~WriteSampleMaskTestCase(void)
1606 {
1607 }
1608
1609 virtual void checkSupport(Context &context) const;
1610 virtual void initPrograms(vk::SourceCollections &programCollection) const;
1611 virtual TestInstance *createInstance(Context &context) const;
1612 static uint32_t getBufferElems(uint32_t sampleCount);
1613
1614 static const tcu::Vec4 kClearColor;
1615 static const tcu::Vec4 kWriteColor;
1616
1617 static constexpr vk::VkFormat kImageFormat = vk::VK_FORMAT_R8G8B8A8_UNORM;
1618 static constexpr vk::VkImageUsageFlags kUsageFlags =
1619 (vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT);
1620 static constexpr vk::VkFormatFeatureFlags kFeatureFlags = (vk::VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT);
1621
1622 private:
1623 WriteSampleMaskParams m_params;
1624 };
1625
1626 const tcu::Vec4 WriteSampleMaskTestCase::kClearColor{0.0f, 0.0f, 0.0f, 1.0f};
1627 const tcu::Vec4 WriteSampleMaskTestCase::kWriteColor{0.0f, 0.0f, 1.0f, 1.0f};
1628
1629 class WriteSampleMaskTestInstance : public vkt::TestInstance
1630 {
1631 public:
1632 WriteSampleMaskTestInstance(Context &context, const WriteSampleMaskParams ¶ms);
~WriteSampleMaskTestInstance(void)1633 virtual ~WriteSampleMaskTestInstance(void)
1634 {
1635 }
1636
1637 virtual tcu::TestStatus iterate(void);
1638
1639 private:
1640 WriteSampleMaskParams m_params;
1641 };
1642
WriteSampleMaskTestCase(tcu::TestContext & testCtx,const std::string & name,const WriteSampleMaskParams & params)1643 WriteSampleMaskTestCase::WriteSampleMaskTestCase(tcu::TestContext &testCtx, const std::string &name,
1644 const WriteSampleMaskParams ¶ms)
1645 : vkt::TestCase(testCtx, name)
1646 , m_params(params)
1647 {
1648 }
1649
checkSupport(Context & context) const1650 void WriteSampleMaskTestCase::checkSupport(Context &context) const
1651 {
1652 const auto &vki = context.getInstanceInterface();
1653 const auto physicalDevice = context.getPhysicalDevice();
1654
1655 // Check if sampleRateShading is supported.
1656 if (!vk::getPhysicalDeviceFeatures(vki, physicalDevice).sampleRateShading)
1657 TCU_THROW(NotSupportedError, "Sample rate shading is not supported");
1658
1659 // Check the specific image format.
1660 const auto properties = vk::getPhysicalDeviceFormatProperties(vki, physicalDevice, kImageFormat);
1661 if (!(properties.optimalTilingFeatures & kFeatureFlags))
1662 TCU_THROW(NotSupportedError, "Format does not support the required features");
1663
1664 // Check the supported sample count.
1665 const auto imgProps = vk::getPhysicalDeviceImageFormatProperties(
1666 vki, physicalDevice, kImageFormat, vk::VK_IMAGE_TYPE_2D, vk::VK_IMAGE_TILING_OPTIMAL, kUsageFlags, 0u);
1667 if (!(imgProps.sampleCounts & m_params.sampleCount))
1668 TCU_THROW(NotSupportedError, "Format does not support the required sample count");
1669
1670 checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
1671 m_params.pipelineConstructionType);
1672 }
1673
initPrograms(vk::SourceCollections & programCollection) const1674 void WriteSampleMaskTestCase::initPrograms(vk::SourceCollections &programCollection) const
1675 {
1676 const auto bpc = de::toString(bitsPerCoord(m_params.sampleCount));
1677 const auto size = imageSize(m_params.sampleCount);
1678 const auto bufferElems = getBufferElems(m_params.sampleCount);
1679
1680 // Passthrough vertex shader.
1681 std::ostringstream vertShader;
1682
1683 vertShader << "#version 450\n"
1684 << "layout (location=0) in vec2 inPos;\n"
1685 << "void main()\n"
1686 << "{\n"
1687 << " gl_Position = vec4(inPos, 0.0, 1.0);\n"
1688 << "}\n";
1689
1690 // Fragment shader common header.
1691 std::ostringstream fragHeader;
1692
1693 fragHeader
1694 << "#version 450\n"
1695 << "\n"
1696 // The color attachment is useless for the second subpass but avoids having to use an empty subpass and verifying the sample
1697 // count is valid for it.
1698 << "layout (location=0) out vec4 outColor;\n"
1699 << "\n"
1700 << "vec4 wcolor = " << getShaderDecl(kWriteColor) << ";\n"
1701 << "vec4 ccolor = " << getShaderDecl(kClearColor) << ";\n"
1702 << "\n";
1703
1704 const auto fragHeaderStr = fragHeader.str();
1705
1706 // Fragment shader setting the sample mask and writing to the output color attachment. The sample mask will guarantee each image
1707 // pixel gets a different combination of sample bits set, allowing the fragment shader to write in that sample or not, from all
1708 // zeros in pixel (0, 0) to all ones in the opposite corner.
1709 std::ostringstream fragShaderWrite;
1710
1711 fragShaderWrite << fragHeaderStr << "void main()\n"
1712 << "{\n"
1713 << " uvec2 ucoords = uvec2(gl_FragCoord);\n"
1714 << " ivec2 icoords = ivec2(ucoords);\n"
1715 << " gl_SampleMask[0] = int((ucoords.x << " << bpc << ") | ucoords.y);\n"
1716 << " outColor = wcolor;\n"
1717 << "}\n";
1718
1719 // Fragment shader reading from the previous output color attachment and copying the state to an SSBO for verification.
1720 std::ostringstream fragShaderCheck;
1721
1722 const bool isMultiSample = (m_params.sampleCount != vk::VK_SAMPLE_COUNT_1_BIT);
1723 fragShaderCheck << fragHeaderStr << "layout(set=0, binding=0, input_attachment_index=0) uniform subpassInput"
1724 << (isMultiSample ? "MS" : "") << " inputAttachment;\n"
1725 << "layout(set=0, binding=1, std430) buffer StorageBuffer {\n"
1726 << " int writeFlags[" << bufferElems << "];\n"
1727 << "} sb;\n"
1728 << "\n"
1729 << "void main()\n"
1730 << "{\n"
1731 << " uvec2 ucoords = uvec2(gl_FragCoord);\n"
1732 << " ivec2 icoords = ivec2(ucoords);\n"
1733 << " uint bufferp = ((ucoords.y * " << size.width << " + ucoords.x) * "
1734 << m_params.sampleCount << ") + uint(gl_SampleID);\n"
1735 << " vec4 storedc = subpassLoad(inputAttachment"
1736 << (isMultiSample ? ", gl_SampleID" : "") << ");\n"
1737 << " sb.writeFlags[bufferp] = ((storedc == wcolor) ? 1 : ((storedc == ccolor) ? 0 : 2));\n"
1738 << " outColor = storedc;\n"
1739 << "}\n";
1740
1741 programCollection.glslSources.add("vert") << glu::VertexSource(vertShader.str());
1742 programCollection.glslSources.add("frag_write") << glu::FragmentSource(fragShaderWrite.str());
1743 programCollection.glslSources.add("frag_check") << glu::FragmentSource(fragShaderCheck.str());
1744 }
1745
createInstance(Context & context) const1746 TestInstance *WriteSampleMaskTestCase::createInstance(Context &context) const
1747 {
1748 return new WriteSampleMaskTestInstance(context, m_params);
1749 }
1750
getBufferElems(uint32_t sampleCount)1751 uint32_t WriteSampleMaskTestCase::getBufferElems(uint32_t sampleCount)
1752 {
1753 const auto imgSize = imageSize(sampleCount);
1754 return (imgSize.width * imgSize.height * sampleCount);
1755 }
1756
WriteSampleMaskTestInstance(Context & context,const WriteSampleMaskParams & params)1757 WriteSampleMaskTestInstance::WriteSampleMaskTestInstance(Context &context, const WriteSampleMaskParams ¶ms)
1758 : vkt::TestInstance(context)
1759 , m_params(params)
1760 {
1761 }
1762
iterate(void)1763 tcu::TestStatus WriteSampleMaskTestInstance::iterate(void)
1764 {
1765 const auto &vki = m_context.getInstanceInterface();
1766 const auto &vkd = m_context.getDeviceInterface();
1767 const auto physicalDevice = m_context.getPhysicalDevice();
1768 const auto device = m_context.getDevice();
1769 auto &alloc = m_context.getDefaultAllocator();
1770 const auto queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
1771 const auto queue = m_context.getUniversalQueue();
1772
1773 static constexpr auto kImageFormat = WriteSampleMaskTestCase::kImageFormat;
1774 static constexpr auto kImageUsage = WriteSampleMaskTestCase::kUsageFlags;
1775 const auto kImageExtent = getExtent3D(m_params.sampleCount);
1776 const auto kBufferElems = WriteSampleMaskTestCase::getBufferElems(m_params.sampleCount);
1777 const auto kBufferSize = static_cast<vk::VkDeviceSize>(kBufferElems * sizeof(int32_t));
1778
1779 // Create image.
1780 const vk::VkImageCreateInfo imageCreateInfo = {
1781 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
1782 nullptr, // const void* pNext;
1783 0u, // VkImageCreateFlags flags;
1784 vk::VK_IMAGE_TYPE_2D, // VkImageType imageType;
1785 kImageFormat, // VkFormat format;
1786 kImageExtent, // VkExtent3D extent;
1787 1u, // uint32_t mipLevels;
1788 1u, // uint32_t arrayLayers;
1789 m_params.sampleCount, // VkSampleCountFlagBits samples;
1790 vk::VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
1791 kImageUsage, // VkImageUsageFlags usage;
1792 vk::VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1793 0u, // uint32_t queueFamilyIndexCount;
1794 nullptr, // const uint32_t* pQueueFamilyIndices;
1795 vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
1796 };
1797
1798 const vk::ImageWithMemory colorImage(vkd, device, alloc, imageCreateInfo, vk::MemoryRequirement::Any);
1799 const vk::ImageWithMemory auxiliarImage(vkd, device, alloc, imageCreateInfo,
1800 vk::MemoryRequirement::Any); // For the second subpass.
1801
1802 // Image views.
1803 const auto subresourceRange = vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
1804 const auto colorImageView =
1805 vk::makeImageView(vkd, device, colorImage.get(), vk::VK_IMAGE_VIEW_TYPE_2D, kImageFormat, subresourceRange);
1806 const auto auxiliarImageView =
1807 vk::makeImageView(vkd, device, auxiliarImage.get(), vk::VK_IMAGE_VIEW_TYPE_2D, kImageFormat, subresourceRange);
1808
1809 // Create storage buffer used to verify results.
1810 const vk::BufferWithMemory storageBuffer(
1811 vkd, device, alloc, vk::makeBufferCreateInfo(kBufferSize, vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT),
1812 vk::MemoryRequirement::HostVisible);
1813
1814 // Full-screen quad.
1815 const std::vector<tcu::Vec2> quadVertices = {
1816 tcu::Vec2(-1.0f, 1.0f), // Lower left
1817 tcu::Vec2(1.0f, 1.0f), // Lower right
1818 tcu::Vec2(1.0f, -1.0f), // Top right.
1819 tcu::Vec2(-1.0f, 1.0f), // Lower left
1820 tcu::Vec2(1.0f, -1.0f), // Top right.
1821 tcu::Vec2(-1.0f, -1.0f), // Top left.
1822 };
1823
1824 // Vertex buffer.
1825 const auto vertexBufferSize =
1826 static_cast<vk::VkDeviceSize>(quadVertices.size() * sizeof(decltype(quadVertices)::value_type));
1827 const vk::BufferWithMemory vertexBuffer(
1828 vkd, device, alloc, vk::makeBufferCreateInfo(vertexBufferSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
1829 vk::MemoryRequirement::HostVisible);
1830 const auto &vertexBufferAlloc = vertexBuffer.getAllocation();
1831 void *vertexBufferPtr = vertexBufferAlloc.getHostPtr();
1832 const vk::VkDeviceSize vertexBufferOffset = 0;
1833 deMemcpy(vertexBufferPtr, quadVertices.data(), static_cast<size_t>(vertexBufferSize));
1834 vk::flushAlloc(vkd, device, vertexBufferAlloc);
1835
1836 // Descriptor set layout.
1837 vk::DescriptorSetLayoutBuilder setLayoutBuilder;
1838 setLayoutBuilder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, vk::VK_SHADER_STAGE_FRAGMENT_BIT);
1839 setLayoutBuilder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_FRAGMENT_BIT);
1840 const auto descriptorSetLayout = setLayoutBuilder.build(vkd, device);
1841
1842 // Descriptor pool and set.
1843 vk::DescriptorPoolBuilder poolBuilder;
1844 poolBuilder.addType(vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1u);
1845 poolBuilder.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u);
1846 const auto descriptorPool =
1847 poolBuilder.build(vkd, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1848 const auto descriptorSet = vk::makeDescriptorSet(vkd, device, descriptorPool.get(), descriptorSetLayout.get());
1849
1850 // Render pass.
1851 const std::vector<vk::VkAttachmentDescription> attachments = {
1852 // Main color attachment.
1853 {
1854 0u, // VkAttachmentDescriptionFlags flags;
1855 kImageFormat, // VkFormat format;
1856 m_params.sampleCount, // VkSampleCountFlagBits samples;
1857 vk::VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
1858 vk::VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
1859 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
1860 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
1861 vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
1862 vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // VkImageLayout finalLayout;
1863 },
1864 // Auxiliar color attachment for the check pass.
1865 {
1866 0u, // VkAttachmentDescriptionFlags flags;
1867 kImageFormat, // VkFormat format;
1868 m_params.sampleCount, // VkSampleCountFlagBits samples;
1869 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp loadOp;
1870 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp storeOp;
1871 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
1872 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
1873 vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
1874 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
1875 },
1876 };
1877
1878 const vk::VkAttachmentReference colorAttachmentReference = {
1879 0u, // uint32_t attachment;
1880 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout layout;
1881 };
1882
1883 const vk::VkAttachmentReference colorAsInputAttachment = {
1884 0u, // uint32_t attachment;
1885 vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // VkImageLayout layout;
1886 };
1887
1888 const vk::VkAttachmentReference auxiliarAttachmentReference = {
1889 1u, // uint32_t attachment;
1890 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout layout;
1891 };
1892
1893 const std::vector<vk::VkSubpassDescription> subpasses = {
1894 // First subpass writing to the main attachment.
1895 {
1896 0u, // VkSubpassDescriptionFlags flags;
1897 vk::VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
1898 0u, // uint32_t inputAttachmentCount;
1899 nullptr, // const VkAttachmentReference* pInputAttachments;
1900 1u, // uint32_t colorAttachmentCount;
1901 &colorAttachmentReference, // const VkAttachmentReference* pColorAttachments;
1902 nullptr, // const VkAttachmentReference* pResolveAttachments;
1903 nullptr, // const VkAttachmentReference* pDepthStencilAttachment;
1904 0u, // uint32_t preserveAttachmentCount;
1905 nullptr, // const uint32_t* pPreserveAttachments;
1906 },
1907 // Second subpass writing to the auxiliar attachment.
1908 {
1909 0u, // VkSubpassDescriptionFlags flags;
1910 vk::VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
1911 1u, // uint32_t inputAttachmentCount;
1912 &colorAsInputAttachment, // const VkAttachmentReference* pInputAttachments;
1913 1u, // uint32_t colorAttachmentCount;
1914 &auxiliarAttachmentReference, // const VkAttachmentReference* pColorAttachments;
1915 nullptr, // const VkAttachmentReference* pResolveAttachments;
1916 nullptr, // const VkAttachmentReference* pDepthStencilAttachment;
1917 0u, // uint32_t preserveAttachmentCount;
1918 nullptr, // const uint32_t* pPreserveAttachments;
1919 },
1920 };
1921
1922 const std::vector<vk::VkSubpassDependency> subpassDependencies = {
1923 // First subpass writes to the color attachment and second subpass reads it as an input attachment.
1924 {
1925 0u, // uint32_t srcSubpass;
1926 1u, // uint32_t dstSubpass;
1927 vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags srcStageMask;
1928 vk::VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, // VkPipelineStageFlags dstStageMask;
1929 vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask;
1930 vk::VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, // VkAccessFlags dstAccessMask;
1931 0u, // VkDependencyFlags dependencyFlags;
1932 },
1933 };
1934
1935 const vk::VkRenderPassCreateInfo renderPassInfo = {
1936 vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
1937 nullptr, // const void* pNext;
1938 0u, // VkRenderPassCreateFlags flags;
1939 static_cast<uint32_t>(attachments.size()), // uint32_t attachmentCount;
1940 attachments.data(), // const VkAttachmentDescription* pAttachments;
1941 static_cast<uint32_t>(subpasses.size()), // uint32_t subpassCount;
1942 subpasses.data(), // const VkSubpassDescription* pSubpasses;
1943 static_cast<uint32_t>(subpassDependencies.size()), // uint32_t dependencyCount;
1944 subpassDependencies.data(), // const VkSubpassDependency* pDependencies;
1945 };
1946 RenderPassWrapper renderPass(m_params.pipelineConstructionType, vkd, device, &renderPassInfo);
1947
1948 // Framebuffer.
1949 const std::vector<vk::VkImage> images = {
1950 colorImage.get(),
1951 auxiliarImage.get(),
1952 };
1953 const std::vector<vk::VkImageView> imageViews = {
1954 colorImageView.get(),
1955 auxiliarImageView.get(),
1956 };
1957 renderPass.createFramebuffer(vkd, device, static_cast<uint32_t>(imageViews.size()), images.data(),
1958 imageViews.data(), kImageExtent.width, kImageExtent.height);
1959
1960 // Empty pipeline layout for the first subpass.
1961 const PipelineLayoutWrapper emptyPipelineLayout(m_params.pipelineConstructionType, vkd, device);
1962
1963 // Pipeline layout for the second subpass.
1964 const PipelineLayoutWrapper checkPipelineLayout(m_params.pipelineConstructionType, vkd, device,
1965 descriptorSetLayout.get());
1966
1967 // Shader modules.
1968 const auto vertModule = ShaderWrapper(vkd, device, m_context.getBinaryCollection().get("vert"), 0u);
1969 const auto writeModule = ShaderWrapper(vkd, device, m_context.getBinaryCollection().get("frag_write"), 0u);
1970 const auto checkModule = ShaderWrapper(vkd, device, m_context.getBinaryCollection().get("frag_check"), 0u);
1971
1972 const std::vector<vk::VkVertexInputBindingDescription> vertexBindings = {
1973 {
1974 0u, // uint32_t binding;
1975 static_cast<uint32_t>(sizeof(decltype(quadVertices)::value_type)), // uint32_t stride;
1976 vk::VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate;
1977 },
1978 };
1979
1980 const std::vector<vk::VkVertexInputAttributeDescription> vertexAttributes = {
1981 {
1982 0u, // uint32_t location;
1983 0u, // uint32_t binding;
1984 vk::VK_FORMAT_R32G32_SFLOAT, // VkFormat format;
1985 0u, // uint32_t offset;
1986 },
1987 };
1988
1989 const vk::VkPipelineVertexInputStateCreateInfo vertexInputInfo = {
1990 vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
1991 nullptr, // const void* pNext;
1992 0u, // VkPipelineVertexInputStateCreateFlags flags;
1993 static_cast<uint32_t>(vertexBindings.size()), // uint32_t vertexBindingDescriptionCount;
1994 vertexBindings.data(), // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
1995 static_cast<uint32_t>(vertexAttributes.size()), // uint32_t vertexAttributeDescriptionCount;
1996 vertexAttributes.data(), // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
1997 };
1998
1999 const vk::VkPipelineInputAssemblyStateCreateInfo inputAssemblyInfo = {
2000 vk::VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
2001 nullptr, // const void* pNext;
2002 0u, // VkPipelineInputAssemblyStateCreateFlags flags;
2003 vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // VkPrimitiveTopology topology;
2004 VK_FALSE, // VkBool32 primitiveRestartEnable;
2005 };
2006
2007 const std::vector<VkViewport> viewport{vk::makeViewport(kImageExtent)};
2008 const std::vector<VkRect2D> scissor{vk::makeRect2D(kImageExtent)};
2009
2010 const vk::VkPipelineMultisampleStateCreateInfo multisampleInfo = {
2011 vk::VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
2012 nullptr, // const void* pNext;
2013 0u, // VkPipelineMultisampleStateCreateFlags flags;
2014 m_params.sampleCount, // VkSampleCountFlagBits rasterizationSamples;
2015 VK_FALSE, // VkBool32 sampleShadingEnable;
2016 1.0f, // float minSampleShading;
2017 nullptr, // const VkSampleMask* pSampleMask;
2018 VK_FALSE, // VkBool32 alphaToCoverageEnable;
2019 VK_FALSE, // VkBool32 alphaToOneEnable;
2020 };
2021
2022 const auto stencilState =
2023 vk::makeStencilOpState(vk::VK_STENCIL_OP_KEEP, vk::VK_STENCIL_OP_KEEP, vk::VK_STENCIL_OP_KEEP,
2024 vk::VK_COMPARE_OP_ALWAYS, 0xFFu, 0xFFu, 0u);
2025
2026 const vk::VkPipelineDepthStencilStateCreateInfo depthStencilInfo = {
2027 vk::VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
2028 nullptr, // const void* pNext;
2029 0u, // VkPipelineDepthStencilStateCreateFlags flags;
2030 VK_FALSE, // VkBool32 depthTestEnable;
2031 VK_FALSE, // VkBool32 depthWriteEnable;
2032 vk::VK_COMPARE_OP_ALWAYS, // VkCompareOp depthCompareOp;
2033 VK_FALSE, // VkBool32 depthBoundsTestEnable;
2034 VK_FALSE, // VkBool32 stencilTestEnable;
2035 stencilState, // VkStencilOpState front;
2036 stencilState, // VkStencilOpState back;
2037 0.0f, // float minDepthBounds;
2038 1.0f, // float maxDepthBounds;
2039 };
2040
2041 const vk::VkPipelineColorBlendAttachmentState colorBlendAttachmentState = {
2042 VK_FALSE, // VkBool32 blendEnable;
2043 vk::VK_BLEND_FACTOR_ZERO, // VkBlendFactor srcColorBlendFactor;
2044 vk::VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor;
2045 vk::VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp;
2046 vk::VK_BLEND_FACTOR_ZERO, // VkBlendFactor srcAlphaBlendFactor;
2047 vk::VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor;
2048 vk::VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp;
2049 ( // VkColorComponentFlags colorWriteMask;
2050 vk::VK_COLOR_COMPONENT_R_BIT | vk::VK_COLOR_COMPONENT_G_BIT | vk::VK_COLOR_COMPONENT_B_BIT |
2051 vk::VK_COLOR_COMPONENT_A_BIT),
2052 };
2053
2054 const vk::VkPipelineColorBlendStateCreateInfo colorBlendInfo = {
2055 vk::VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
2056 nullptr, // const void* pNext;
2057 0u, // VkPipelineColorBlendStateCreateFlags flags;
2058 VK_FALSE, // VkBool32 logicOpEnable;
2059 vk::VK_LOGIC_OP_NO_OP, // VkLogicOp logicOp;
2060 1u, // uint32_t attachmentCount;
2061 &colorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
2062 {.0f, .0f, .0f, .0f}, // float blendConstants[4];
2063 };
2064
2065 const vk::VkPipelineDynamicStateCreateInfo dynamicStateInfo = {
2066 vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
2067 nullptr, // const void* pNext;
2068 0u, // VkPipelineDynamicStateCreateFlags flags;
2069 0u, // uint32_t dynamicStateCount;
2070 nullptr, // const VkDynamicState* pDynamicStates;
2071 };
2072
2073 // Pipeline for the first subpass.
2074 vk::GraphicsPipelineWrapper firstSubpassPipeline(vki, vkd, physicalDevice, device, m_context.getDeviceExtensions(),
2075 m_params.pipelineConstructionType);
2076 firstSubpassPipeline.setDynamicState(&dynamicStateInfo)
2077 .setDefaultRasterizationState()
2078 .setupVertexInputState(&vertexInputInfo, &inputAssemblyInfo)
2079 .setupPreRasterizationShaderState(viewport, scissor, emptyPipelineLayout, *renderPass, 0u, vertModule)
2080 .setupFragmentShaderState(emptyPipelineLayout, *renderPass, 0u, writeModule, &depthStencilInfo,
2081 &multisampleInfo)
2082 .setupFragmentOutputState(*renderPass, 0u, &colorBlendInfo, &multisampleInfo)
2083 .setMonolithicPipelineLayout(emptyPipelineLayout)
2084 .buildPipeline();
2085
2086 // Pipeline for the second subpass.
2087 vk::GraphicsPipelineWrapper secondSubpassPipeline(vki, vkd, physicalDevice, device, m_context.getDeviceExtensions(),
2088 m_params.pipelineConstructionType);
2089 secondSubpassPipeline.setDynamicState(&dynamicStateInfo)
2090 .setDefaultRasterizationState()
2091 .setupVertexInputState(&vertexInputInfo, &inputAssemblyInfo)
2092 .setupPreRasterizationShaderState(viewport, scissor, checkPipelineLayout, *renderPass, 1u, vertModule)
2093 .setupFragmentShaderState(checkPipelineLayout, *renderPass, 1u, checkModule, &depthStencilInfo,
2094 &multisampleInfo)
2095 .setupFragmentOutputState(*renderPass, 1u, &colorBlendInfo, &multisampleInfo)
2096 .setMonolithicPipelineLayout(checkPipelineLayout)
2097 .buildPipeline();
2098
2099 // Command pool and command buffer.
2100 const auto cmdPool = vk::makeCommandPool(vkd, device, queueFamilyIndex);
2101 const auto cmdBufferPtr =
2102 vk::allocateCommandBuffer(vkd, device, cmdPool.get(), vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
2103 const auto cmdBuffer = cmdBufferPtr.get();
2104
2105 // Update descriptor set.
2106 vk::DescriptorSetUpdateBuilder updateBuilder;
2107 const auto imageInfo =
2108 vk::makeDescriptorImageInfo(DE_NULL, colorImageView.get(), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
2109 const auto bufferInfo = vk::makeDescriptorBufferInfo(storageBuffer.get(), 0u, VK_WHOLE_SIZE);
2110 updateBuilder.writeSingle(descriptorSet.get(), vk::DescriptorSetUpdateBuilder::Location::binding(0u),
2111 vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, &imageInfo);
2112 updateBuilder.writeSingle(descriptorSet.get(), vk::DescriptorSetUpdateBuilder::Location::binding(1u),
2113 vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &bufferInfo);
2114 updateBuilder.update(vkd, device);
2115
2116 // Output buffer pipeline barrier.
2117 const auto bufferBarrier = vk::makeBufferMemoryBarrier(vk::VK_ACCESS_SHADER_WRITE_BIT, vk::VK_ACCESS_HOST_READ_BIT,
2118 storageBuffer.get(), 0ull, VK_WHOLE_SIZE);
2119
2120 // Run pipelines.
2121 vk::beginCommandBuffer(vkd, cmdBuffer);
2122
2123 renderPass.begin(vkd, cmdBuffer, vk::makeRect2D(kImageExtent), WriteSampleMaskTestCase::kClearColor);
2124 vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
2125 firstSubpassPipeline.bind(cmdBuffer);
2126 vkd.cmdDraw(cmdBuffer, static_cast<uint32_t>(quadVertices.size()), 1u, 0u, 0u);
2127
2128 renderPass.nextSubpass(vkd, cmdBuffer, vk::VK_SUBPASS_CONTENTS_INLINE);
2129 secondSubpassPipeline.bind(cmdBuffer);
2130 vkd.cmdBindDescriptorSets(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, checkPipelineLayout.get(), 0u, 1u,
2131 &descriptorSet.get(), 0u, nullptr);
2132 vkd.cmdDraw(cmdBuffer, static_cast<uint32_t>(quadVertices.size()), 1u, 0u, 0u);
2133
2134 renderPass.end(vkd, cmdBuffer);
2135 vkd.cmdPipelineBarrier(cmdBuffer, vk::VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, vk::VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u,
2136 nullptr, 1u, &bufferBarrier, 0u, nullptr);
2137 vk::endCommandBuffer(vkd, cmdBuffer);
2138
2139 vk::submitCommandsAndWait(vkd, device, queue, cmdBuffer);
2140
2141 // Check buffer contents.
2142 auto &bufferAlloc = storageBuffer.getAllocation();
2143 const void *bufferPtr = bufferAlloc.getHostPtr();
2144 std::vector<int32_t> bufferContents(kBufferElems, 0);
2145
2146 vk::invalidateAlloc(vkd, device, bufferAlloc);
2147 deMemcpy(bufferContents.data(), bufferPtr, static_cast<size_t>(kBufferSize));
2148
2149 const auto sampleCount = static_cast<uint32_t>(m_params.sampleCount);
2150 const auto bpc = bitsPerCoord(sampleCount);
2151
2152 for (uint32_t x = 0; x < kImageExtent.width; ++x)
2153 for (uint32_t y = 0; y < kImageExtent.height; ++y)
2154 {
2155 // Samples on which we expect writes.
2156 const uint32_t sampleMask = ((x << bpc) | y);
2157
2158 // Starting location for the pixel sample values in the buffer.
2159 const uint32_t pixelOffset = (y * kImageExtent.width + x) * sampleCount;
2160
2161 for (uint32_t s = 0; s < sampleCount; ++s)
2162 {
2163 const uint32_t sampleIndex = pixelOffset + s;
2164 const int32_t &value = bufferContents[sampleIndex];
2165
2166 if (value != 0 && value != 1)
2167 {
2168 // Garbage!
2169 std::ostringstream msg;
2170 msg << "Found garbage value " << value << " in buffer position " << sampleIndex << " (x=" << x
2171 << ", y=" << y << ", sample=" << s << ")";
2172 return tcu::TestStatus::fail(msg.str());
2173 }
2174
2175 const int32_t expected = (((sampleMask & (1u << s)) != 0u) ? 1 : 0);
2176 if (value != expected)
2177 {
2178 std::ostringstream msg;
2179 msg << "Read " << value << " while expecting " << expected << " in buffer position " << sampleIndex
2180 << " (x=" << x << ", y=" << y << ", sample=" << s << ")";
2181 return tcu::TestStatus::fail(msg.str());
2182 }
2183 }
2184 }
2185
2186 return tcu::TestStatus::pass("Pass");
2187 }
2188
2189 } // namespace multisample
2190
createMultisampleShaderBuiltInTests(tcu::TestContext & testCtx,vk::PipelineConstructionType pipelineConstructionType)2191 tcu::TestCaseGroup *createMultisampleShaderBuiltInTests(tcu::TestContext &testCtx,
2192 vk::PipelineConstructionType pipelineConstructionType)
2193 {
2194 de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "multisample_shader_builtin"));
2195
2196 const tcu::UVec3 imageSizes[] = {
2197 tcu::UVec3(128u, 128u, 1u),
2198 tcu::UVec3(137u, 191u, 1u),
2199 };
2200
2201 const uint32_t sizesElemCount = static_cast<uint32_t>(sizeof(imageSizes) / sizeof(tcu::UVec3));
2202
2203 const vk::VkSampleCountFlagBits samplesSetFull[] = {
2204 vk::VK_SAMPLE_COUNT_2_BIT, vk::VK_SAMPLE_COUNT_4_BIT, vk::VK_SAMPLE_COUNT_8_BIT,
2205 vk::VK_SAMPLE_COUNT_16_BIT, vk::VK_SAMPLE_COUNT_32_BIT, vk::VK_SAMPLE_COUNT_64_BIT,
2206 };
2207
2208 const uint32_t samplesSetFullCount =
2209 static_cast<uint32_t>(sizeof(samplesSetFull) / sizeof(vk::VkSampleCountFlagBits));
2210
2211 testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseSampleID>>(
2212 testCtx, "sample_id", pipelineConstructionType, imageSizes, sizesElemCount, samplesSetFull,
2213 samplesSetFullCount));
2214
2215 de::MovePtr<tcu::TestCaseGroup> samplePositionGroup(new tcu::TestCaseGroup(testCtx, "sample_position"));
2216
2217 samplePositionGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseSamplePosDistribution>>(
2218 testCtx, "distribution", pipelineConstructionType, imageSizes, sizesElemCount, samplesSetFull,
2219 samplesSetFullCount));
2220 samplePositionGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseSamplePosCorrectness>>(
2221 testCtx, "correctness", pipelineConstructionType, imageSizes, sizesElemCount, samplesSetFull,
2222 samplesSetFullCount));
2223
2224 testGroup->addChild(samplePositionGroup.release());
2225
2226 const vk::VkSampleCountFlagBits samplesSetReduced[] = {
2227 vk::VK_SAMPLE_COUNT_2_BIT, vk::VK_SAMPLE_COUNT_4_BIT, vk::VK_SAMPLE_COUNT_8_BIT,
2228 vk::VK_SAMPLE_COUNT_16_BIT, vk::VK_SAMPLE_COUNT_32_BIT,
2229 };
2230
2231 const uint32_t samplesSetReducedCount = static_cast<uint32_t>(DE_LENGTH_OF_ARRAY(samplesSetReduced));
2232
2233 de::MovePtr<tcu::TestCaseGroup> sampleMaskGroup(new tcu::TestCaseGroup(testCtx, "sample_mask"));
2234
2235 sampleMaskGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseSampleMaskPattern>>(
2236 testCtx, "pattern", pipelineConstructionType, imageSizes, sizesElemCount, samplesSetReduced,
2237 samplesSetReducedCount));
2238 sampleMaskGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseSampleMaskBitCount>>(
2239 testCtx, "bit_count", pipelineConstructionType, imageSizes, sizesElemCount, samplesSetReduced,
2240 samplesSetReducedCount));
2241 sampleMaskGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseSampleMaskBitCount>>(
2242 testCtx, "bit_count_0_5", pipelineConstructionType, imageSizes, sizesElemCount, samplesSetReduced,
2243 samplesSetReducedCount, multisample::ComponentData{}, 0.5f));
2244 sampleMaskGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseSampleMaskCorrectBit>>(
2245 testCtx, "correct_bit", pipelineConstructionType, imageSizes, sizesElemCount, samplesSetReduced,
2246 samplesSetReducedCount));
2247 sampleMaskGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseSampleMaskWrite>>(
2248 testCtx, "write", pipelineConstructionType, imageSizes, sizesElemCount, samplesSetReduced,
2249 samplesSetReducedCount));
2250
2251 testGroup->addChild(sampleMaskGroup.release());
2252
2253 // Write image sample tests using a storage images (tests construct only compute pipeline).
2254 if (pipelineConstructionType == vk::PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC)
2255 {
2256 // Test OpImageWrite with a sample ID
2257 de::MovePtr<tcu::TestCaseGroup> imageWriteSampleGroup(new tcu::TestCaseGroup(testCtx, "image_write_sample"));
2258
2259 for (auto count : multisample::kValidSquareSampleCounts)
2260 {
2261 if (count == vk::VK_SAMPLE_COUNT_1_BIT)
2262 continue;
2263
2264 multisample::WriteSampleParams params{pipelineConstructionType,
2265 static_cast<vk::VkSampleCountFlagBits>(count)};
2266 const auto countStr = de::toString(count);
2267 imageWriteSampleGroup->addChild(new multisample::WriteSampleTest(testCtx, countStr + "_samples", params));
2268 }
2269
2270 testGroup->addChild(imageWriteSampleGroup.release());
2271 }
2272
2273 // Write to gl_SampleMask from the fragment shader.
2274 {
2275 de::MovePtr<tcu::TestCaseGroup> writeSampleMaskGroup(new tcu::TestCaseGroup(testCtx, "write_sample_mask"));
2276
2277 for (auto count : multisample::kValidSquareSampleCounts)
2278 {
2279 multisample::WriteSampleMaskParams params{pipelineConstructionType,
2280 static_cast<vk::VkSampleCountFlagBits>(count)};
2281 const auto countStr = de::toString(count);
2282 writeSampleMaskGroup->addChild(
2283 new multisample::WriteSampleMaskTestCase(testCtx, countStr + "_samples", params));
2284 }
2285
2286 testGroup->addChild(writeSampleMaskGroup.release());
2287 }
2288
2289 return testGroup.release();
2290 }
2291
2292 } // namespace pipeline
2293 } // namespace vkt
2294