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 &params)
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 &params)
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, &copyRegion);
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 &params);
~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 &params);
~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 &params)
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 &params)
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