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 vktPipelineMultisampleInterpolationTests.cpp
23 * \brief Multisample Interpolation Tests
24 *//*--------------------------------------------------------------------*/
25 
26 #include "vktPipelineMultisampleInterpolationTests.hpp"
27 #include "vktPipelineMultisampleBaseResolve.hpp"
28 #include "vktPipelineMultisampleTestsUtil.hpp"
29 #include "vktPipelineMakeUtil.hpp"
30 #include "vktAmberTestCase.hpp"
31 #include "vkQueryUtil.hpp"
32 #include "tcuTestLog.hpp"
33 #include <vector>
34 
35 namespace vkt
36 {
37 namespace pipeline
38 {
39 namespace multisample
40 {
41 
42 using namespace vk;
43 
44 struct VertexDataNdc
45 {
VertexDataNdcvkt::pipeline::multisample::VertexDataNdc46     VertexDataNdc(const tcu::Vec4 &posNdc) : positionNdc(posNdc)
47     {
48     }
49 
50     tcu::Vec4 positionNdc;
51 };
52 
53 struct VertexDataNdcScreen
54 {
VertexDataNdcScreenvkt::pipeline::multisample::VertexDataNdcScreen55     VertexDataNdcScreen(const tcu::Vec4 &posNdc, const tcu::Vec2 &posScreen)
56         : positionNdc(posNdc)
57         , positionScreen(posScreen)
58     {
59     }
60 
61     tcu::Vec4 positionNdc;
62     tcu::Vec2 positionScreen;
63 };
64 
65 struct VertexDataNdcBarycentric
66 {
VertexDataNdcBarycentricvkt::pipeline::multisample::VertexDataNdcBarycentric67     VertexDataNdcBarycentric(const tcu::Vec4 &posNdc, const tcu::Vec3 &barCoord)
68         : positionNdc(posNdc)
69         , barycentricCoord(barCoord)
70     {
71     }
72 
73     tcu::Vec4 positionNdc;
74     tcu::Vec3 barycentricCoord;
75 };
76 
checkForError(const vk::VkImageCreateInfo & imageRSInfo,const tcu::ConstPixelBufferAccess & dataRS,const uint32_t errorCompNdx)77 bool checkForError(const vk::VkImageCreateInfo &imageRSInfo, const tcu::ConstPixelBufferAccess &dataRS,
78                    const uint32_t errorCompNdx)
79 {
80     for (uint32_t z = 0u; z < imageRSInfo.extent.depth; ++z)
81         for (uint32_t y = 0u; y < imageRSInfo.extent.height; ++y)
82             for (uint32_t x = 0u; x < imageRSInfo.extent.width; ++x)
83             {
84                 const uint32_t errorComponent = dataRS.getPixelUint(x, y, z)[errorCompNdx];
85 
86                 if (errorComponent > 0)
87                     return true;
88             }
89 
90     return false;
91 }
92 
93 template <typename CaseClassName>
94 class MSCase : public MultisampleCaseBase
95 {
96 public:
MSCase(tcu::TestContext & testCtx,const std::string & name,const ImageMSParams & imageMSParams)97     MSCase(tcu::TestContext &testCtx, const std::string &name, const ImageMSParams &imageMSParams)
98         : MultisampleCaseBase(testCtx, name, imageMSParams)
99     {
100     }
101 
102     void init(void);
103     void initPrograms(vk::SourceCollections &programCollection) const;
104     void checkSupport(Context &context) const;
105     TestInstance *createInstance(Context &context) const;
106     static MultisampleCaseBase *createCase(tcu::TestContext &testCtx, const std::string &name,
107                                            const ImageMSParams &imageMSParams);
108 };
109 
110 template <typename CaseClassName>
checkSupport(Context & context) const111 void MSCase<CaseClassName>::checkSupport(Context &context) const
112 {
113     checkGraphicsPipelineLibrarySupport(context);
114 
115 #ifndef CTS_USES_VULKANSC
116     if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
117         !context.getPortabilitySubsetFeatures().shaderSampleRateInterpolationFunctions)
118     {
119         TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Shader sample rate interpolation functions are not "
120                                      "supported by this implementation");
121     }
122 #endif // CTS_USES_VULKANSC
123 
124     context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SAMPLE_RATE_SHADING);
125 }
126 
127 template <typename CaseClassName>
createCase(tcu::TestContext & testCtx,const std::string & name,const ImageMSParams & imageMSParams)128 MultisampleCaseBase *MSCase<CaseClassName>::createCase(tcu::TestContext &testCtx, const std::string &name,
129                                                        const ImageMSParams &imageMSParams)
130 {
131     return new MSCase<CaseClassName>(testCtx, name, imageMSParams);
132 }
133 
134 template <typename InstanceClassName>
135 class MSInstance : public MSInstanceBaseResolve
136 {
137 public:
MSInstance(Context & context,const ImageMSParams & imageMSParams)138     MSInstance(Context &context, const ImageMSParams &imageMSParams) : MSInstanceBaseResolve(context, imageMSParams)
139     {
140     }
141 
142     VertexDataDesc getVertexDataDescripton(void) const;
143     void uploadVertexData(const Allocation &vertexBufferAllocation, const VertexDataDesc &vertexDataDescripton) const;
144     tcu::TestStatus verifyImageData(const vk::VkImageCreateInfo &imageRSInfo,
145                                     const tcu::ConstPixelBufferAccess &dataRS) const;
146 };
147 
148 class MSInstanceDistinctValues;
149 
150 template <>
getVertexDataDescripton(void) const151 MultisampleInstanceBase::VertexDataDesc MSInstance<MSInstanceDistinctValues>::getVertexDataDescripton(void) const
152 {
153     VertexDataDesc vertexDataDesc;
154 
155     vertexDataDesc.verticesCount     = 3u;
156     vertexDataDesc.dataStride        = sizeof(VertexDataNdc);
157     vertexDataDesc.dataSize          = vertexDataDesc.verticesCount * vertexDataDesc.dataStride;
158     vertexDataDesc.primitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
159 
160     const VkVertexInputAttributeDescription vertexAttribPositionNdc = {
161         0u,                                   // uint32_t location;
162         0u,                                   // uint32_t binding;
163         VK_FORMAT_R32G32B32A32_SFLOAT,        // VkFormat format;
164         offsetof(VertexDataNdc, positionNdc), // uint32_t offset;
165     };
166 
167     vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionNdc);
168 
169     return vertexDataDesc;
170 }
171 
172 template <>
uploadVertexData(const Allocation & vertexBufferAllocation,const VertexDataDesc & vertexDataDescripton) const173 void MSInstance<MSInstanceDistinctValues>::uploadVertexData(const Allocation &vertexBufferAllocation,
174                                                             const VertexDataDesc &vertexDataDescripton) const
175 {
176     std::vector<VertexDataNdc> vertices;
177 
178     vertices.push_back(VertexDataNdc(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f)));
179     vertices.push_back(VertexDataNdc(tcu::Vec4(-1.0f, 4.0f, 0.0f, 1.0f)));
180     vertices.push_back(VertexDataNdc(tcu::Vec4(4.0f, -1.0f, 0.0f, 1.0f)));
181 
182     deMemcpy(vertexBufferAllocation.getHostPtr(), dataPointer(vertices),
183              static_cast<std::size_t>(vertexDataDescripton.dataSize));
184 }
185 
186 template <>
verifyImageData(const vk::VkImageCreateInfo & imageRSInfo,const tcu::ConstPixelBufferAccess & dataRS) const187 tcu::TestStatus MSInstance<MSInstanceDistinctValues>::verifyImageData(const vk::VkImageCreateInfo &imageRSInfo,
188                                                                       const tcu::ConstPixelBufferAccess &dataRS) const
189 {
190     const uint32_t distinctValuesExpected = static_cast<uint32_t>(m_imageMSParams.numSamples) + 1u;
191 
192     std::vector<tcu::IVec4> distinctValues;
193 
194     for (uint32_t z = 0u; z < imageRSInfo.extent.depth; ++z)
195         for (uint32_t y = 0u; y < imageRSInfo.extent.height; ++y)
196             for (uint32_t x = 0u; x < imageRSInfo.extent.width; ++x)
197             {
198                 const tcu::IVec4 pixel = dataRS.getPixelInt(x, y, z);
199 
200                 if (std::find(distinctValues.begin(), distinctValues.end(), pixel) == distinctValues.end())
201                     distinctValues.push_back(pixel);
202             }
203 
204     if (distinctValues.size() >= distinctValuesExpected)
205         return tcu::TestStatus::pass("Passed");
206     else
207         return tcu::TestStatus::fail("Expected numSamples+1 different colors in the output image");
208 }
209 
210 class MSCaseSampleQualifierDistinctValues;
211 
212 template <>
init(void)213 void MSCase<MSCaseSampleQualifierDistinctValues>::init(void)
214 {
215     m_testCtx.getLog()
216         << tcu::TestLog::Message
217         << "Verifying that a sample qualified varying is given different values for different samples.\n"
218         << "    Render full screen traingle with quadratic function defining red/green color pattern division.\n"
219         << " => Resulting image should contain n+1 different colors, where n = sample count.\n"
220         << tcu::TestLog::EndMessage;
221 
222     MultisampleCaseBase::init();
223 }
224 
225 template <>
initPrograms(vk::SourceCollections & programCollection) const226 void MSCase<MSCaseSampleQualifierDistinctValues>::initPrograms(vk::SourceCollections &programCollection) const
227 {
228     // Create vertex shader
229     std::ostringstream vs;
230 
231     vs << "#version 440\n"
232        << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
233        << "\n"
234        << "layout(location = 0) out vec4 vs_out_position_ndc;\n"
235        << "\n"
236        << "out gl_PerVertex {\n"
237        << "    vec4  gl_Position;\n"
238        << "};\n"
239        << "void main (void)\n"
240        << "{\n"
241        << "    gl_Position = vs_in_position_ndc;\n"
242        << "    vs_out_position_ndc = vs_in_position_ndc;\n"
243        << "}\n";
244 
245     programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
246 
247     // Create fragment shader
248     std::ostringstream fs;
249 
250     fs << "#version 440\n"
251        << "layout(location = 0) sample in vec4 fs_in_position_ndc;\n"
252        << "\n"
253        << "layout(location = 0) out vec4 fs_out_color;\n"
254        << "\n"
255        << "void main (void)\n"
256        << "{\n"
257        << "    if(fs_in_position_ndc.y < -2.0*pow(0.5*(fs_in_position_ndc.x + 1.0), 2.0) + 1.0)\n"
258        << "        fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
259        << "    else\n"
260        << "        fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
261        << "}\n";
262 
263     programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
264 }
265 
266 template <>
checkSupport(Context & context) const267 void MSCase<MSCaseSampleQualifierDistinctValues>::checkSupport(Context &context) const
268 {
269     checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
270                                           m_imageMSParams.pipelineConstructionType);
271 
272     context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SAMPLE_RATE_SHADING);
273 }
274 
275 template <>
createInstance(Context & context) const276 TestInstance *MSCase<MSCaseSampleQualifierDistinctValues>::createInstance(Context &context) const
277 {
278     return new MSInstance<MSInstanceDistinctValues>(context, m_imageMSParams);
279 }
280 
281 class MSCaseInterpolateAtSampleDistinctValues;
282 
283 template <>
init(void)284 void MSCase<MSCaseInterpolateAtSampleDistinctValues>::init(void)
285 {
286     m_testCtx.getLog()
287         << tcu::TestLog::Message
288         << "Verifying that a interpolateAtSample returns different values for different samples.\n"
289         << "    Render full screen traingle with quadratic function defining red/green color pattern division.\n"
290         << " => Resulting image should contain n+1 different colors, where n = sample count.\n"
291         << tcu::TestLog::EndMessage;
292 
293     MultisampleCaseBase::init();
294 }
295 
296 template <>
initPrograms(vk::SourceCollections & programCollection) const297 void MSCase<MSCaseInterpolateAtSampleDistinctValues>::initPrograms(vk::SourceCollections &programCollection) const
298 {
299     // Create vertex shader
300     std::ostringstream vs;
301 
302     vs << "#version 440\n"
303        << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
304        << "\n"
305        << "layout(location = 0) out vec4 vs_out_position_ndc;\n"
306        << "\n"
307        << "out gl_PerVertex {\n"
308        << "    vec4  gl_Position;\n"
309        << "};\n"
310        << "void main (void)\n"
311        << "{\n"
312        << "    gl_Position = vs_in_position_ndc;\n"
313        << "    vs_out_position_ndc = vs_in_position_ndc;\n"
314        << "}\n";
315 
316     programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
317 
318     // Create fragment shader
319     std::ostringstream fs;
320 
321     fs << "#version 440\n"
322        << "layout(location = 0) in vec4 fs_in_position_ndc;\n"
323        << "\n"
324        << "layout(location = 0) out vec4 fs_out_color;\n"
325        << "\n"
326        << "void main (void)\n"
327        << "{\n"
328        << "    const vec4 position_ndc_at_sample = interpolateAtSample(fs_in_position_ndc, gl_SampleID);\n"
329        << "    if(position_ndc_at_sample.y < -2.0*pow(0.5*(position_ndc_at_sample.x + 1.0), 2.0) + 1.0)\n"
330        << "        fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
331        << "    else\n"
332        << "        fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
333        << "}\n";
334 
335     programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
336 }
337 
338 template <>
createInstance(Context & context) const339 TestInstance *MSCase<MSCaseInterpolateAtSampleDistinctValues>::createInstance(Context &context) const
340 {
341     return new MSInstance<MSInstanceDistinctValues>(context, m_imageMSParams);
342 }
343 
344 class MSInstanceInterpolateScreenPosition;
345 
346 template <>
getVertexDataDescripton(void) const347 MSInstanceBaseResolve::VertexDataDesc MSInstance<MSInstanceInterpolateScreenPosition>::getVertexDataDescripton(
348     void) const
349 {
350     VertexDataDesc vertexDataDesc;
351 
352     vertexDataDesc.verticesCount     = 4u;
353     vertexDataDesc.dataStride        = sizeof(VertexDataNdcScreen);
354     vertexDataDesc.dataSize          = vertexDataDesc.verticesCount * vertexDataDesc.dataStride;
355     vertexDataDesc.primitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
356 
357     const VkVertexInputAttributeDescription vertexAttribPositionNdc = {
358         0u,                                         // uint32_t location;
359         0u,                                         // uint32_t binding;
360         VK_FORMAT_R32G32B32A32_SFLOAT,              // VkFormat format;
361         offsetof(VertexDataNdcScreen, positionNdc), // uint32_t offset;
362     };
363 
364     vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionNdc);
365 
366     const VkVertexInputAttributeDescription vertexAttribPositionScreen = {
367         1u,                                            // uint32_t location;
368         0u,                                            // uint32_t binding;
369         VK_FORMAT_R32G32_SFLOAT,                       // VkFormat format;
370         offsetof(VertexDataNdcScreen, positionScreen), // uint32_t offset;
371     };
372 
373     vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionScreen);
374 
375     return vertexDataDesc;
376 }
377 
378 template <>
uploadVertexData(const Allocation & vertexBufferAllocation,const VertexDataDesc & vertexDataDescripton) const379 void MSInstance<MSInstanceInterpolateScreenPosition>::uploadVertexData(const Allocation &vertexBufferAllocation,
380                                                                        const VertexDataDesc &vertexDataDescripton) const
381 {
382     const tcu::UVec3 layerSize = getLayerSize(IMAGE_TYPE_2D, m_imageMSParams.imageSize);
383     const float screenSizeX    = static_cast<float>(layerSize.x());
384     const float screenSizeY    = static_cast<float>(layerSize.y());
385 
386     std::vector<VertexDataNdcScreen> vertices;
387 
388     vertices.push_back(VertexDataNdcScreen(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec2(0.0f, 0.0f)));
389     vertices.push_back(VertexDataNdcScreen(tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec2(screenSizeX, 0.0f)));
390     vertices.push_back(VertexDataNdcScreen(tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f), tcu::Vec2(0.0f, screenSizeY)));
391     vertices.push_back(VertexDataNdcScreen(tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f), tcu::Vec2(screenSizeX, screenSizeY)));
392 
393     deMemcpy(vertexBufferAllocation.getHostPtr(), dataPointer(vertices),
394              static_cast<std::size_t>(vertexDataDescripton.dataSize));
395 }
396 
397 template <>
verifyImageData(const vk::VkImageCreateInfo & imageRSInfo,const tcu::ConstPixelBufferAccess & dataRS) const398 tcu::TestStatus MSInstance<MSInstanceInterpolateScreenPosition>::verifyImageData(
399     const vk::VkImageCreateInfo &imageRSInfo, const tcu::ConstPixelBufferAccess &dataRS) const
400 {
401     if (checkForError(imageRSInfo, dataRS, 0))
402         return tcu::TestStatus::fail("Failed");
403 
404     return tcu::TestStatus::pass("Passed");
405 }
406 
407 class MSCaseInterpolateAtSampleSingleSample;
408 
409 template <>
init(void)410 void MSCase<MSCaseInterpolateAtSampleSingleSample>::init(void)
411 {
412     m_testCtx.getLog() << tcu::TestLog::Message
413                        << "Verifying that using interpolateAtSample with multisample buffers not available returns "
414                           "sample evaluated at the center of the pixel.\n"
415                        << "    Interpolate varying containing screen space location.\n"
416                        << " => fract(screen space location) should be (about) (0.5, 0.5)\n"
417                        << tcu::TestLog::EndMessage;
418 
419     MultisampleCaseBase::init();
420 }
421 
422 template <>
initPrograms(vk::SourceCollections & programCollection) const423 void MSCase<MSCaseInterpolateAtSampleSingleSample>::initPrograms(vk::SourceCollections &programCollection) const
424 {
425     // Create vertex shader
426     std::ostringstream vs;
427 
428     vs << "#version 440\n"
429        << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
430        << "layout(location = 1) in vec2 vs_in_position_screen;\n"
431        << "\n"
432        << "layout(location = 0) out vec2 vs_out_position_screen;\n"
433        << "\n"
434        << "out gl_PerVertex {\n"
435        << "    vec4  gl_Position;\n"
436        << "};\n"
437        << "void main (void)\n"
438        << "{\n"
439        << "    gl_Position = vs_in_position_ndc;\n"
440        << "    vs_out_position_screen = vs_in_position_screen;\n"
441        << "}\n";
442 
443     programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
444 
445     // Create fragment shader
446     std::ostringstream fs;
447 
448     fs << "#version 440\n"
449        << "layout(location = 0) in vec2 fs_in_position_screen;\n"
450        << "\n"
451        << "layout(location = 0) out vec4 fs_out_color;\n"
452        << "\n"
453        << "void main (void)\n"
454        << "{\n"
455        << "    const float threshold = 0.15625;\n"
456        << "    const vec2  position_screen_at_sample = interpolateAtSample(fs_in_position_screen, 0);\n"
457        << "    const vec2  position_inside_pixel = fract(position_screen_at_sample);\n"
458        << "\n"
459        << "    if (abs(position_inside_pixel.x - 0.5) <= threshold && abs(position_inside_pixel.y - 0.5) <= "
460           "threshold)\n"
461        << "        fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
462        << "    else\n"
463        << "        fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
464        << "}\n";
465 
466     programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
467 }
468 
469 template <>
createInstance(Context & context) const470 TestInstance *MSCase<MSCaseInterpolateAtSampleSingleSample>::createInstance(Context &context) const
471 {
472     return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
473 }
474 
475 class MSCaseInterpolateAtSampleIgnoresCentroid;
476 
477 template <>
init(void)478 void MSCase<MSCaseInterpolateAtSampleIgnoresCentroid>::init(void)
479 {
480     m_testCtx.getLog()
481         << tcu::TestLog::Message << "Verifying that interpolateAtSample ignores centroid qualifier.\n"
482         << "    Interpolate varying containing screen space location with centroid and sample qualifiers.\n"
483         << " => interpolateAtSample(screenSample, n) ~= interpolateAtSample(screenCentroid, n)\n"
484         << tcu::TestLog::EndMessage;
485 
486     MultisampleCaseBase::init();
487 }
488 
489 template <>
initPrograms(vk::SourceCollections & programCollection) const490 void MSCase<MSCaseInterpolateAtSampleIgnoresCentroid>::initPrograms(vk::SourceCollections &programCollection) const
491 {
492     // Create vertex shader
493     std::ostringstream vs;
494 
495     vs << "#version 440\n"
496        << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
497        << "layout(location = 1) in vec2 vs_in_position_screen;\n"
498        << "\n"
499        << "layout(location = 0) out vec2 vs_out_pos_screen_centroid;\n"
500        << "layout(location = 1) out vec2 vs_out_pos_screen_fragment;\n"
501        << "\n"
502        << "out gl_PerVertex {\n"
503        << "    vec4  gl_Position;\n"
504        << "};\n"
505        << "void main (void)\n"
506        << "{\n"
507        << "    gl_Position = vs_in_position_ndc;\n"
508        << "    vs_out_pos_screen_centroid = vs_in_position_screen;\n"
509        << "    vs_out_pos_screen_fragment = vs_in_position_screen;\n"
510        << "}\n";
511 
512     programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
513 
514     // Create fragment shader
515     std::ostringstream fs;
516 
517     fs << "#version 440\n"
518        << "layout(location = 0) centroid in vec2 fs_in_pos_screen_centroid;\n"
519        << "layout(location = 1)          in vec2 fs_in_pos_screen_fragment;\n"
520        << "\n"
521        << "layout(location = 0) out vec4 fs_out_color;\n"
522        << "\n"
523        << "void main (void)\n"
524        << "{\n"
525        << "    const float threshold = 0.0005;\n"
526        << "\n"
527        << "    const vec2 position_a  = interpolateAtSample(fs_in_pos_screen_centroid, gl_SampleID);\n"
528        << "    const vec2 position_b  = interpolateAtSample(fs_in_pos_screen_fragment, gl_SampleID);\n"
529        << "    const bool valuesEqual = all(lessThan(abs(position_a - position_b), vec2(threshold)));\n"
530        << "\n"
531        << "    if (valuesEqual)\n"
532        << "        fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
533        << "    else\n"
534        << "        fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
535        << "}\n";
536 
537     programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
538 }
539 
540 template <>
createInstance(Context & context) const541 TestInstance *MSCase<MSCaseInterpolateAtSampleIgnoresCentroid>::createInstance(Context &context) const
542 {
543     return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
544 }
545 
546 class MSCaseInterpolateAtSampleConsistency;
547 
548 template <>
init(void)549 void MSCase<MSCaseInterpolateAtSampleConsistency>::init(void)
550 {
551     const std::string indexStr = de::toString(m_imageMSParams.componentData.index);
552     std::string componentMsg;
553 
554     switch (m_imageMSParams.componentData.source)
555     {
556     case multisample::ComponentSource::CONSTANT:
557         componentMsg = "Using single constant component " + indexStr;
558         break;
559     case multisample::ComponentSource::PUSH_CONSTANT:
560         componentMsg = "Using single component via push constant " + indexStr;
561         break;
562     default:
563         break;
564     }
565 
566     m_testCtx.getLog()
567         << tcu::TestLog::Message
568         << "Verifying that interpolateAtSample with the sample set to the current sampleID returns consistent values.\n"
569         << (componentMsg.empty() ? std::string() : componentMsg + "\n")
570         << "    Interpolate varying containing screen space location with centroid and sample qualifiers.\n"
571         << " => interpolateAtSample(screenCentroid, sampleID) = screenSample\n"
572         << tcu::TestLog::EndMessage;
573 
574     MultisampleCaseBase::init();
575 }
576 
577 template <>
initPrograms(vk::SourceCollections & programCollection) const578 void MSCase<MSCaseInterpolateAtSampleConsistency>::initPrograms(vk::SourceCollections &programCollection) const
579 {
580     // Create vertex shader
581     std::ostringstream vs;
582 
583     vs << "#version 440\n"
584        << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
585        << "layout(location = 1) in vec2 vs_in_position_screen;\n"
586        << "\n"
587        << "layout(location = 0) out vec2 vs_out_pos_screen_centroid;\n"
588        << "layout(location = 1) out vec2 vs_out_pos_screen_sample;\n"
589        << "\n"
590        << "out gl_PerVertex {\n"
591        << "    vec4  gl_Position;\n"
592        << "};\n"
593        << "void main (void)\n"
594        << "{\n"
595        << "    gl_Position = vs_in_position_ndc;\n"
596        << "    vs_out_pos_screen_centroid = vs_in_position_screen;\n"
597        << "    vs_out_pos_screen_sample = vs_in_position_screen;\n"
598        << "}\n";
599 
600     programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
601 
602     // Create fragment shader
603     std::ostringstream fs;
604 
605     fs << "#version 440\n"
606        << "layout(location = 0) centroid in vec2 fs_in_pos_screen_centroid;\n"
607        << "layout(location = 1) sample   in vec2 fs_in_pos_screen_sample;\n"
608        << "\n"
609        << "layout(location = 0) out vec4 fs_out_color;\n"
610        << "\n";
611 
612     if (m_imageMSParams.componentData.source == multisample::ComponentSource::PUSH_CONSTANT)
613     {
614         fs << "layout(push_constant) uniform PushConstants {\n"
615            << "   uint component;\n"
616            << "};\n"
617            << "\n";
618     }
619 
620     fs << "void main (void)\n"
621        << "{\n"
622        << "    const float threshold = 0.15625;\n"
623        << "\n";
624 
625     if (m_imageMSParams.componentData.source == multisample::ComponentSource::NONE)
626     {
627         fs << "    const vec2  pos_interpolated_at_sample = interpolateAtSample(fs_in_pos_screen_centroid, "
628               "gl_SampleID);\n"
629            << "    const bool  valuesEqual                = all(lessThan(abs(pos_interpolated_at_sample - "
630               "fs_in_pos_screen_sample), vec2(threshold)));\n";
631     }
632     else if (m_imageMSParams.componentData.source == multisample::ComponentSource::CONSTANT)
633     {
634         const auto &index = m_imageMSParams.componentData.index;
635         fs << "    const float pos_interpolated_at_sample = interpolateAtSample(fs_in_pos_screen_centroid[" << index
636            << "], gl_SampleID);\n"
637            << "    const bool  valuesEqual                = (abs(pos_interpolated_at_sample - fs_in_pos_screen_sample["
638            << index << "]) < threshold);\n";
639     }
640     else // multisample::ComponentSource::PUSH_CONSTANT
641     {
642         fs << "    const float pos_interpolated_at_sample = interpolateAtSample(fs_in_pos_screen_centroid[component], "
643               "gl_SampleID);\n"
644            << "    const bool  valuesEqual                = (abs(pos_interpolated_at_sample - "
645               "fs_in_pos_screen_sample[component]) < threshold);\n";
646     }
647 
648     fs << "\n"
649        << "    if (valuesEqual)\n"
650        << "        fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
651        << "    else\n"
652        << "        fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
653        << "}\n";
654 
655     programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
656 }
657 
658 template <>
createInstance(Context & context) const659 TestInstance *MSCase<MSCaseInterpolateAtSampleConsistency>::createInstance(Context &context) const
660 {
661     return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
662 }
663 
664 class MSCaseInterpolateAtCentroidConsistency;
665 
666 template <>
init(void)667 void MSCase<MSCaseInterpolateAtCentroidConsistency>::init(void)
668 {
669     const std::string indexStr = de::toString(m_imageMSParams.componentData.index);
670     std::string componentMsg;
671 
672     switch (m_imageMSParams.componentData.source)
673     {
674     case multisample::ComponentSource::CONSTANT:
675         componentMsg = "Using single constant component " + indexStr;
676         break;
677     case multisample::ComponentSource::PUSH_CONSTANT:
678         componentMsg = "Using single component via push constant " + indexStr;
679         break;
680     default:
681         break;
682     }
683 
684     m_testCtx.getLog()
685         << tcu::TestLog::Message
686         << "Verifying that interpolateAtCentroid does not return different values than a corresponding "
687            "centroid qualified varying.\n"
688         << (componentMsg.empty() ? std::string() : componentMsg + "\n")
689         << "    Interpolate varying containing screen space location with sample and centroid qualifiers.\n"
690         << " => interpolateAtCentroid(screenSample) = screenCentroid\n"
691         << tcu::TestLog::EndMessage;
692 
693     MultisampleCaseBase::init();
694 }
695 
696 template <>
initPrograms(vk::SourceCollections & programCollection) const697 void MSCase<MSCaseInterpolateAtCentroidConsistency>::initPrograms(vk::SourceCollections &programCollection) const
698 {
699     // Create vertex shader
700     std::ostringstream vs;
701 
702     vs << "#version 440\n"
703        << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
704        << "layout(location = 1) in vec2 vs_in_position_screen;\n"
705        << "\n"
706        << "layout(location = 0) out vec2 vs_out_pos_screen_sample[2];\n"
707        << "layout(location = 2) out vec2 vs_out_pos_screen_centroid[2];\n"
708        << "\n"
709        << "out gl_PerVertex {\n"
710        << "    vec4  gl_Position;\n"
711        << "};\n"
712        << "void main (void)\n"
713        << "{\n"
714        << "    gl_Position                      = vs_in_position_ndc;\n"
715        // Index 0 is never read, so we'll populate them with bad values
716        << "    vs_out_pos_screen_sample[0]      = vec2(-70.3, 42.1);\n"
717        << "    vs_out_pos_screen_centroid[0] = vec2(7.7, -3.2);\n"
718        // Actual coordinates in index 1:
719        << "    vs_out_pos_screen_sample[1]      = vs_in_position_screen;\n"
720        << "    vs_out_pos_screen_centroid[1] = vs_in_position_screen;\n"
721        << "}\n";
722 
723     programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
724 
725     // Create fragment shader
726     std::ostringstream fs;
727 
728     fs << "#version 440\n"
729        << "layout(location = 0) sample   in vec2 fs_in_pos_screen_sample[2];\n"
730        << "layout(location = 2) centroid in vec2 fs_in_pos_screen_centroid[2];\n"
731        << "\n"
732        << "layout(location = 0) out vec4 fs_out_color;\n"
733        << "\n";
734 
735     if (m_imageMSParams.componentData.source == multisample::ComponentSource::PUSH_CONSTANT)
736     {
737         fs << "layout(push_constant) uniform PushConstants {\n"
738            << "   uint component;\n"
739            << "};\n"
740            << "\n";
741     }
742 
743     fs << "void main (void)\n"
744        << "{\n"
745        << "    const float threshold = 0.0005;\n"
746        << "\n";
747 
748     if (m_imageMSParams.componentData.source == multisample::ComponentSource::NONE)
749     {
750         fs << "    const vec2 pos_interpolated_at_centroid = interpolateAtCentroid(fs_in_pos_screen_sample[1]);\n"
751            << "    const bool valuesEqual                  = all(lessThan(abs(pos_interpolated_at_centroid - "
752               "fs_in_pos_screen_centroid[1]), vec2(threshold)));\n";
753     }
754     else if (m_imageMSParams.componentData.source == multisample::ComponentSource::CONSTANT)
755     {
756         const auto &index = m_imageMSParams.componentData.index;
757         fs << "    const float pos_interpolated_at_centroid = interpolateAtCentroid(fs_in_pos_screen_sample[1]["
758            << index << "]);\n"
759            << "    const bool  valuesEqual                  = (abs(pos_interpolated_at_centroid - "
760               "fs_in_pos_screen_centroid[1]["
761            << index << "]) < threshold);\n";
762     }
763     else // multisample::ComponentSource::PUSH_CONSTANT
764     {
765         fs << "    const float pos_interpolated_at_centroid = "
766               "interpolateAtCentroid(fs_in_pos_screen_sample[1][component]);\n"
767            << "    const bool  valuesEqual                  = (abs(pos_interpolated_at_centroid - "
768               "fs_in_pos_screen_centroid[1][component]) < threshold);\n";
769     }
770 
771     fs << "\n"
772        << "    if (valuesEqual)\n"
773        << "        fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
774        << "    else\n"
775        << "        fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
776        << "}\n";
777 
778     programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
779 }
780 
781 template <>
createInstance(Context & context) const782 TestInstance *MSCase<MSCaseInterpolateAtCentroidConsistency>::createInstance(Context &context) const
783 {
784     return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
785 }
786 
787 class MSCaseInterpolateAtOffsetPixelCenter;
788 
789 template <>
init(void)790 void MSCase<MSCaseInterpolateAtOffsetPixelCenter>::init(void)
791 {
792     m_testCtx.getLog()
793         << tcu::TestLog::Message
794         << "Verifying that interpolateAtOffset returns value sampled at an offset from the center of the pixel.\n"
795         << "    Interpolate varying containing screen space location.\n"
796         << " => interpolateAtOffset(screen, offset) should be \"varying value at the pixel center\" + offset"
797         << tcu::TestLog::EndMessage;
798 
799     MultisampleCaseBase::init();
800 }
801 
802 template <>
initPrograms(vk::SourceCollections & programCollection) const803 void MSCase<MSCaseInterpolateAtOffsetPixelCenter>::initPrograms(vk::SourceCollections &programCollection) const
804 {
805     // Create vertex shader
806     std::ostringstream vs;
807 
808     vs << "#version 440\n"
809        << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
810        << "layout(location = 1) in vec2 vs_in_position_screen;\n"
811        << "\n"
812        << "layout(location = 0) out vec2 vs_out_pos_screen;\n"
813        << "layout(location = 1) out vec2 vs_out_offset;\n"
814        << "\n"
815        << "out gl_PerVertex {\n"
816        << "    vec4  gl_Position;\n"
817        << "};\n"
818        << "void main (void)\n"
819        << "{\n"
820        << "    gl_Position = vs_in_position_ndc;\n"
821        << "    vs_out_pos_screen = vs_in_position_screen;\n"
822        << "    vs_out_offset = vs_in_position_ndc.xy * 0.5;\n"
823        << "}\n";
824 
825     programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
826 
827     // Create fragment shader
828     std::ostringstream fs;
829 
830     fs << "#version 440\n"
831        << "layout(location = 0) in  vec2 fs_in_pos_screen;\n"
832        << "layout(location = 1) in  vec2 fs_in_offset;\n"
833        << "\n"
834        << "layout(location = 0) out vec4 fs_out_color;\n"
835        << "\n"
836        << "void main (void)\n"
837        << "{\n"
838        << "    const vec2  frag_center = interpolateAtOffset(fs_in_pos_screen, vec2(0.0));\n"
839        << "    const vec2  center_diff = abs(frag_center - fs_in_pos_screen);\n"
840        << "    const float threshold   = 0.125;\n"
841        << "    bool        valuesEqual = false;\n"
842        << "\n"
843        << "    if (all(lessThan(center_diff, vec2(0.5 + threshold)))) {\n"
844        << "        const vec2 pos_interpolated_at_offset = interpolateAtOffset(fs_in_pos_screen, fs_in_offset);\n"
845        << "        const vec2 reference_value            = frag_center + fs_in_offset;\n"
846        << "\n"
847        << "        valuesEqual = all(lessThan(abs(pos_interpolated_at_offset - reference_value), vec2(threshold)));\n"
848        << "    }\n"
849        << "\n"
850        << "    if (valuesEqual)\n"
851        << "        fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
852        << "    else\n"
853        << "        fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
854        << "}\n";
855 
856     programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
857 }
858 
859 template <>
createInstance(Context & context) const860 TestInstance *MSCase<MSCaseInterpolateAtOffsetPixelCenter>::createInstance(Context &context) const
861 {
862     return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
863 }
864 
865 class MSCaseInterpolateAtOffsetSamplePosition;
866 
867 template <>
init(void)868 void MSCase<MSCaseInterpolateAtOffsetSamplePosition>::init(void)
869 {
870     const std::string indexStr = de::toString(m_imageMSParams.componentData.index);
871     std::string componentMsg;
872 
873     switch (m_imageMSParams.componentData.source)
874     {
875     case multisample::ComponentSource::CONSTANT:
876         componentMsg = "Using single constant component " + indexStr;
877         break;
878     case multisample::ComponentSource::PUSH_CONSTANT:
879         componentMsg = "Using single component via push constant " + indexStr;
880         break;
881     default:
882         break;
883     }
884 
885     m_testCtx.getLog()
886         << tcu::TestLog::Message
887         << "Verifying that interpolateAtOffset of screen position with the offset of current sample "
888            "position returns value "
889         << "similar to screen position interpolated at sample.\n"
890         << (componentMsg.empty() ? std::string() : componentMsg + "\n")
891         << "    Interpolate varying containing screen space location with and without sample qualifier.\n"
892         << " => interpolateAtOffset(screenFragment, samplePosition - (0.5,0.5)) = screenSample"
893         << tcu::TestLog::EndMessage;
894 
895     MultisampleCaseBase::init();
896 }
897 
898 template <>
initPrograms(vk::SourceCollections & programCollection) const899 void MSCase<MSCaseInterpolateAtOffsetSamplePosition>::initPrograms(vk::SourceCollections &programCollection) const
900 {
901     // Create vertex shader
902     std::ostringstream vs;
903 
904     vs << "#version 440\n"
905        << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
906        << "layout(location = 1) in vec2 vs_in_position_screen;\n"
907        << "\n"
908        << "layout(location = 0) out vec2 vs_out_pos_screen_fragment;\n"
909        << "layout(location = 1) out vec2 vs_out_pos_screen_sample;\n"
910        << "\n"
911        << "out gl_PerVertex {\n"
912        << "    vec4  gl_Position;\n"
913        << "};\n"
914        << "void main (void)\n"
915        << "{\n"
916        << "    gl_Position = vs_in_position_ndc;\n"
917        << "    vs_out_pos_screen_fragment = vs_in_position_screen;\n"
918        << "    vs_out_pos_screen_sample = vs_in_position_screen;\n"
919        << "}\n";
920 
921     programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
922 
923     // Create fragment shader
924     std::ostringstream fs;
925 
926     fs << "#version 440\n"
927        << "layout(location = 0)        in vec2 fs_in_pos_screen_fragment;\n"
928        << "layout(location = 1) sample in vec2 fs_in_pos_screen_sample;\n"
929        << "\n"
930        << "layout(location = 0) out vec4 fs_out_color;\n"
931        << "\n";
932 
933     if (m_imageMSParams.componentData.source == multisample::ComponentSource::PUSH_CONSTANT)
934     {
935         fs << "layout(push_constant) uniform PushConstants {\n"
936            << "   uint component;\n"
937            << "};\n"
938            << "\n";
939     }
940 
941     fs << "void main (void)\n"
942        << "{\n"
943        << "    const float threshold = 0.15625;\n"
944        << "\n"
945        << "    const vec2 offset                     = gl_SamplePosition - vec2(0.5, 0.5);\n";
946 
947     if (m_imageMSParams.componentData.source == multisample::ComponentSource::NONE)
948     {
949         fs << "    const vec2 pos_interpolated_at_offset = interpolateAtOffset(fs_in_pos_screen_fragment, offset);\n"
950            << "    const bool valuesEqual                = all(lessThan(abs(pos_interpolated_at_offset - "
951               "fs_in_pos_screen_sample), vec2(threshold)));\n";
952     }
953     else if (m_imageMSParams.componentData.source == multisample::ComponentSource::CONSTANT)
954     {
955         const auto &index = m_imageMSParams.componentData.index;
956         fs << "    const float pos_interpolated_at_offset = interpolateAtOffset(fs_in_pos_screen_fragment[" << index
957            << "], offset);\n"
958            << "    const bool valuesEqual                 = (abs(pos_interpolated_at_offset - fs_in_pos_screen_sample["
959            << index << "]) < threshold);\n";
960     }
961     else // multisample::ComponentSource::PUSH_CONSTANT
962     {
963         fs << "    const float pos_interpolated_at_offset = interpolateAtOffset(fs_in_pos_screen_fragment[component], "
964               "offset);\n"
965            << "    const bool valuesEqual                 = (abs(pos_interpolated_at_offset - "
966               "fs_in_pos_screen_sample[component]) < threshold);\n";
967     }
968 
969     fs << "\n"
970        << "    if (valuesEqual)\n"
971        << "        fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
972        << "    else\n"
973        << "        fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
974        << "}\n";
975 
976     programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
977 }
978 
979 template <>
createInstance(Context & context) const980 TestInstance *MSCase<MSCaseInterpolateAtOffsetSamplePosition>::createInstance(Context &context) const
981 {
982     return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
983 }
984 
985 class MSInstanceInterpolateBarycentricCoordinates;
986 
987 template <>
getVertexDataDescripton(void) const988 MSInstanceBaseResolve::VertexDataDesc MSInstance<MSInstanceInterpolateBarycentricCoordinates>::getVertexDataDescripton(
989     void) const
990 {
991     VertexDataDesc vertexDataDesc;
992 
993     vertexDataDesc.verticesCount     = 3u;
994     vertexDataDesc.dataStride        = sizeof(VertexDataNdcBarycentric);
995     vertexDataDesc.dataSize          = vertexDataDesc.verticesCount * vertexDataDesc.dataStride;
996     vertexDataDesc.primitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
997 
998     const VkVertexInputAttributeDescription vertexAttribPositionNdc = {
999         0u,                                              // uint32_t location;
1000         0u,                                              // uint32_t binding;
1001         VK_FORMAT_R32G32B32A32_SFLOAT,                   // VkFormat format;
1002         offsetof(VertexDataNdcBarycentric, positionNdc), // uint32_t offset;
1003     };
1004 
1005     vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionNdc);
1006 
1007     const VkVertexInputAttributeDescription vertexAttrBarCoord = {
1008         1u,                                                   // uint32_t location;
1009         0u,                                                   // uint32_t binding;
1010         VK_FORMAT_R32G32B32_SFLOAT,                           // VkFormat format;
1011         offsetof(VertexDataNdcBarycentric, barycentricCoord), // uint32_t offset;
1012     };
1013 
1014     vertexDataDesc.vertexAttribDescVec.push_back(vertexAttrBarCoord);
1015 
1016     return vertexDataDesc;
1017 }
1018 
1019 template <>
uploadVertexData(const Allocation & vertexBufferAllocation,const VertexDataDesc & vertexDataDescripton) const1020 void MSInstance<MSInstanceInterpolateBarycentricCoordinates>::uploadVertexData(
1021     const Allocation &vertexBufferAllocation, const VertexDataDesc &vertexDataDescripton) const
1022 {
1023     // Create buffer storing vertex data
1024     std::vector<VertexDataNdcBarycentric> vertices;
1025 
1026     vertices.push_back(VertexDataNdcBarycentric(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec3(0.0f, 0.0f, 1.0f)));
1027     vertices.push_back(VertexDataNdcBarycentric(tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f), tcu::Vec3(1.0f, 0.0f, 0.0f)));
1028     vertices.push_back(VertexDataNdcBarycentric(tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec3(0.0f, 1.0f, 0.0f)));
1029 
1030     deMemcpy(vertexBufferAllocation.getHostPtr(), dataPointer(vertices),
1031              static_cast<std::size_t>(vertexDataDescripton.dataSize));
1032 }
1033 
1034 template <>
verifyImageData(const vk::VkImageCreateInfo & imageRSInfo,const tcu::ConstPixelBufferAccess & dataRS) const1035 tcu::TestStatus MSInstance<MSInstanceInterpolateBarycentricCoordinates>::verifyImageData(
1036     const vk::VkImageCreateInfo &imageRSInfo, const tcu::ConstPixelBufferAccess &dataRS) const
1037 {
1038     if (checkForError(imageRSInfo, dataRS, 0))
1039         return tcu::TestStatus::fail("Failed");
1040 
1041     return tcu::TestStatus::pass("Passed");
1042 }
1043 
1044 class MSCaseCentroidQualifierInsidePrimitive;
1045 
1046 template <>
init(void)1047 void MSCase<MSCaseCentroidQualifierInsidePrimitive>::init(void)
1048 {
1049     m_testCtx.getLog() << tcu::TestLog::Message
1050                        << "Verifying that varying qualified with centroid is interpolated at location inside both the "
1051                           "pixel and the primitive being processed.\n"
1052                        << "    Interpolate triangle's barycentric coordinates with centroid qualifier.\n"
1053                        << " => After interpolation we expect barycentric.xyz >= 0.0 && barycentric.xyz <= 1.0\n"
1054                        << tcu::TestLog::EndMessage;
1055 
1056     MultisampleCaseBase::init();
1057 }
1058 
1059 template <>
initPrograms(vk::SourceCollections & programCollection) const1060 void MSCase<MSCaseCentroidQualifierInsidePrimitive>::initPrograms(vk::SourceCollections &programCollection) const
1061 {
1062     // Create vertex shader
1063     std::ostringstream vs;
1064 
1065     vs << "#version 440\n"
1066        << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
1067        << "layout(location = 1) in vec3 vs_in_barCoord;\n"
1068        << "\n"
1069        << "layout(location = 0) out vec3 vs_out_barCoord;\n"
1070        << "\n"
1071        << "out gl_PerVertex {\n"
1072        << "    vec4  gl_Position;\n"
1073        << "};\n"
1074        << "void main (void)\n"
1075        << "{\n"
1076        << "    gl_Position = vs_in_position_ndc;\n"
1077        << "    vs_out_barCoord = vs_in_barCoord;\n"
1078        << "}\n";
1079 
1080     programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
1081 
1082     // Create fragment shader
1083     std::ostringstream fs;
1084 
1085     fs << "#version 440\n"
1086        << "layout(location = 0) centroid in vec3 fs_in_barCoord;\n"
1087        << "\n"
1088        << "layout(location = 0) out vec4 fs_out_color;\n"
1089        << "\n"
1090        << "void main (void)\n"
1091        << "{\n"
1092        << "    if( all(greaterThanEqual(fs_in_barCoord, vec3(0.0))) && all(lessThanEqual(fs_in_barCoord, vec3(1.0))) "
1093           ")\n"
1094        << "            fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
1095        << "    else\n"
1096        << "            fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
1097        << "}\n";
1098 
1099     programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
1100 }
1101 
1102 template <>
checkSupport(Context & context) const1103 void MSCase<MSCaseCentroidQualifierInsidePrimitive>::checkSupport(Context &context) const
1104 {
1105     checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
1106                                           m_imageMSParams.pipelineConstructionType);
1107 }
1108 
1109 template <>
createInstance(Context & context) const1110 TestInstance *MSCase<MSCaseCentroidQualifierInsidePrimitive>::createInstance(Context &context) const
1111 {
1112     return new MSInstance<MSInstanceInterpolateBarycentricCoordinates>(context, m_imageMSParams);
1113 }
1114 
1115 } // namespace multisample
1116 
createMultisampleInterpolationTests(tcu::TestContext & testCtx,vk::PipelineConstructionType pipelineConstructionType)1117 tcu::TestCaseGroup *createMultisampleInterpolationTests(tcu::TestContext &testCtx,
1118                                                         vk::PipelineConstructionType pipelineConstructionType)
1119 {
1120     de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "multisample_interpolation"));
1121 
1122     const tcu::UVec3 imageSizes[] = {
1123         tcu::UVec3(128u, 128u, 1u),
1124         tcu::UVec3(137u, 191u, 1u),
1125     };
1126 
1127     const uint32_t sizesElemCount = static_cast<uint32_t>(sizeof(imageSizes) / sizeof(tcu::UVec3));
1128 
1129     const vk::VkSampleCountFlagBits imageSamples[] = {
1130         vk::VK_SAMPLE_COUNT_2_BIT,  vk::VK_SAMPLE_COUNT_4_BIT,  vk::VK_SAMPLE_COUNT_8_BIT,
1131         vk::VK_SAMPLE_COUNT_16_BIT, vk::VK_SAMPLE_COUNT_32_BIT, vk::VK_SAMPLE_COUNT_64_BIT,
1132     };
1133 
1134     const uint32_t samplesElemCount = static_cast<uint32_t>(sizeof(imageSamples) / sizeof(vk::VkSampleCountFlagBits));
1135 
1136     de::MovePtr<tcu::TestCaseGroup> caseGroup(new tcu::TestCaseGroup(testCtx, "sample_interpolate_at_single_sample"));
1137 
1138     for (uint32_t imageSizeNdx = 0u; imageSizeNdx < sizesElemCount; ++imageSizeNdx)
1139     {
1140         const tcu::UVec3 imageSize = imageSizes[imageSizeNdx];
1141         std::ostringstream imageSizeStream;
1142 
1143         imageSizeStream << imageSize.x() << "_" << imageSize.y() << "_" << imageSize.z();
1144 
1145         de::MovePtr<tcu::TestCaseGroup> sizeGroup(new tcu::TestCaseGroup(testCtx, imageSizeStream.str().c_str()));
1146 
1147         multisample::ImageMSParams imageParams{
1148             pipelineConstructionType, vk::VK_SAMPLE_COUNT_1_BIT, imageSize, multisample::ComponentData{}, 1.0f,
1149         };
1150         sizeGroup->addChild(multisample::MSCase<multisample::MSCaseInterpolateAtSampleSingleSample>::createCase(
1151             testCtx, "samples_" + de::toString(1), imageParams));
1152 
1153         caseGroup->addChild(sizeGroup.release());
1154     }
1155 
1156     testGroup->addChild(caseGroup.release());
1157 
1158     testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtSampleDistinctValues>>(
1159         testCtx, "sample_interpolate_at_distinct_values", pipelineConstructionType, imageSizes, sizesElemCount,
1160         imageSamples, samplesElemCount));
1161     testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtSampleIgnoresCentroid>>(
1162         testCtx, "sample_interpolate_at_ignores_centroid", pipelineConstructionType, imageSizes, sizesElemCount,
1163         imageSamples, samplesElemCount));
1164 
1165     // Test consistency in sample interpolation function
1166     de::MovePtr<tcu::TestCaseGroup> sampleGroup(new tcu::TestCaseGroup(testCtx, "sample_interpolation_consistency"));
1167     sampleGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtSampleConsistency>>(
1168         testCtx, "all_components", pipelineConstructionType, imageSizes, sizesElemCount, imageSamples,
1169         samplesElemCount));
1170     sampleGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtSampleConsistency>>(
1171         testCtx, "component_0", pipelineConstructionType, imageSizes, sizesElemCount, imageSamples, samplesElemCount,
1172         multisample::ComponentData{multisample::ComponentSource::CONSTANT, 0u}));
1173     sampleGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtSampleConsistency>>(
1174         testCtx, "component_1", pipelineConstructionType, imageSizes, sizesElemCount, imageSamples, samplesElemCount,
1175         multisample::ComponentData{multisample::ComponentSource::CONSTANT, 1u}));
1176     sampleGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtSampleConsistency>>(
1177         testCtx, "pushc_component_0", pipelineConstructionType, imageSizes, sizesElemCount, imageSamples,
1178         samplesElemCount, multisample::ComponentData{multisample::ComponentSource::PUSH_CONSTANT, 0u}));
1179     sampleGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtSampleConsistency>>(
1180         testCtx, "pushc_component_1", pipelineConstructionType, imageSizes, sizesElemCount, imageSamples,
1181         samplesElemCount, multisample::ComponentData{multisample::ComponentSource::PUSH_CONSTANT, 1u}));
1182     testGroup->addChild(sampleGroup.release());
1183 
1184     testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseSampleQualifierDistinctValues>>(
1185         testCtx, "sample_qualifier_distinct_values", pipelineConstructionType, imageSizes, sizesElemCount, imageSamples,
1186         samplesElemCount));
1187 
1188     // Test consistency in centroid interpolation function
1189     de::MovePtr<tcu::TestCaseGroup> centroidGroup(
1190         new tcu::TestCaseGroup(testCtx, "centroid_interpolation_consistency"));
1191     centroidGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtCentroidConsistency>>(
1192         testCtx, "all_components", pipelineConstructionType, imageSizes, sizesElemCount, imageSamples,
1193         samplesElemCount));
1194     centroidGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtCentroidConsistency>>(
1195         testCtx, "component_0", pipelineConstructionType, imageSizes, sizesElemCount, imageSamples, samplesElemCount,
1196         multisample::ComponentData{multisample::ComponentSource::CONSTANT, 0u}));
1197     centroidGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtCentroidConsistency>>(
1198         testCtx, "component_1", pipelineConstructionType, imageSizes, sizesElemCount, imageSamples, samplesElemCount,
1199         multisample::ComponentData{multisample::ComponentSource::CONSTANT, 1u}));
1200     centroidGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtCentroidConsistency>>(
1201         testCtx, "pushc_component_0", pipelineConstructionType, imageSizes, sizesElemCount, imageSamples,
1202         samplesElemCount, multisample::ComponentData{multisample::ComponentSource::PUSH_CONSTANT, 0u}));
1203     centroidGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtCentroidConsistency>>(
1204         testCtx, "pushc_component_1", pipelineConstructionType, imageSizes, sizesElemCount, imageSamples,
1205         samplesElemCount, multisample::ComponentData{multisample::ComponentSource::PUSH_CONSTANT, 1u}));
1206     testGroup->addChild(centroidGroup.release());
1207 
1208 #ifndef CTS_USES_VULKANSC
1209     // there is no support for pipelineConstructionType in amber
1210     if (pipelineConstructionType == vk::PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC)
1211     {
1212         de::MovePtr<tcu::TestCaseGroup> reInterpolationGroup(
1213             new tcu::TestCaseGroup(testCtx, "reinterpolation_consistency"));
1214         std::vector<std::string> requirements;
1215         requirements.push_back("Features.sampleRateShading");
1216         reInterpolationGroup->addChild(cts_amber::createAmberTestCase(
1217             testCtx, "interpolate_at_centroid", "", "pipeline", "reinterpolate_at_centroid.amber", requirements));
1218         reInterpolationGroup->addChild(cts_amber::createAmberTestCase(testCtx, "interpolate_at_sample", "", "pipeline",
1219                                                                       "reinterpolate_at_sample.amber", requirements));
1220         testGroup->addChild(reInterpolationGroup.release());
1221 
1222         de::MovePtr<tcu::TestCaseGroup> nonuniformInterpolantIndexingGroup(
1223             new tcu::TestCaseGroup(testCtx, "nonuniform_interpolant_indexing"));
1224         std::vector<std::string> requirementsNonuniformIntepolantIndexing;
1225         requirementsNonuniformIntepolantIndexing.push_back("Features.sampleRateShading");
1226         nonuniformInterpolantIndexingGroup->addChild(
1227             cts_amber::createAmberTestCase(testCtx, "centroid", "pipeline/nonuniform_interpolant_indexing",
1228                                            "centroid.amber", requirementsNonuniformIntepolantIndexing));
1229         nonuniformInterpolantIndexingGroup->addChild(
1230             cts_amber::createAmberTestCase(testCtx, "sample", "pipeline/nonuniform_interpolant_indexing",
1231                                            "sample.amber", requirementsNonuniformIntepolantIndexing));
1232         nonuniformInterpolantIndexingGroup->addChild(
1233             cts_amber::createAmberTestCase(testCtx, "offset", "pipeline/nonuniform_interpolant_indexing",
1234                                            "offset.amber", requirementsNonuniformIntepolantIndexing));
1235         testGroup->addChild(nonuniformInterpolantIndexingGroup.release());
1236     }
1237 
1238     testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseCentroidQualifierInsidePrimitive>>(
1239         testCtx, "centroid_qualifier_inside_primitive", pipelineConstructionType, imageSizes, sizesElemCount,
1240         imageSamples, samplesElemCount));
1241 #endif // CTS_USES_VULKANSC
1242     testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtOffsetPixelCenter>>(
1243         testCtx, "offset_interpolate_at_pixel_center", pipelineConstructionType, imageSizes, sizesElemCount,
1244         imageSamples, samplesElemCount));
1245 
1246     de::MovePtr<tcu::TestCaseGroup> offsetGroup(
1247         new tcu::TestCaseGroup(testCtx, "offset_interpolation_at_sample_position"));
1248     offsetGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtOffsetSamplePosition>>(
1249         testCtx, "all_components", pipelineConstructionType, imageSizes, sizesElemCount, imageSamples,
1250         samplesElemCount));
1251     offsetGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtOffsetSamplePosition>>(
1252         testCtx, "component_0", pipelineConstructionType, imageSizes, sizesElemCount, imageSamples, samplesElemCount,
1253         multisample::ComponentData{multisample::ComponentSource::CONSTANT, 0u}));
1254     offsetGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtOffsetSamplePosition>>(
1255         testCtx, "component_1", pipelineConstructionType, imageSizes, sizesElemCount, imageSamples, samplesElemCount,
1256         multisample::ComponentData{multisample::ComponentSource::CONSTANT, 1u}));
1257     offsetGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtOffsetSamplePosition>>(
1258         testCtx, "pushc_component_0", pipelineConstructionType, imageSizes, sizesElemCount, imageSamples,
1259         samplesElemCount, multisample::ComponentData{multisample::ComponentSource::PUSH_CONSTANT, 0u}));
1260     offsetGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtOffsetSamplePosition>>(
1261         testCtx, "pushc_component_1", pipelineConstructionType, imageSizes, sizesElemCount, imageSamples,
1262         samplesElemCount, multisample::ComponentData{multisample::ComponentSource::PUSH_CONSTANT, 1u}));
1263     testGroup->addChild(offsetGroup.release());
1264 
1265     return testGroup.release();
1266 }
1267 
1268 } // namespace pipeline
1269 } // namespace vkt
1270