1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2016 The Khronos Group Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*
20 * \file vktPipelineMultisampleInterpolationTests.cpp
21 * \brief Multisample Interpolation Tests
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktPipelineMultisampleInterpolationTests.hpp"
25 #include "vktPipelineMultisampleBaseResolve.hpp"
26 #include "vktPipelineMultisampleTestsUtil.hpp"
27 #include "vktPipelineMakeUtil.hpp"
28 #include "vkQueryUtil.hpp"
29 #include "tcuTestLog.hpp"
30 #include <vector>
31
32 namespace vkt
33 {
34 namespace pipeline
35 {
36 namespace multisample
37 {
38
39 using namespace vk;
40
41 struct VertexDataNdc
42 {
VertexDataNdcvkt::pipeline::multisample::VertexDataNdc43 VertexDataNdc (const tcu::Vec4& posNdc) : positionNdc(posNdc) {}
44
45 tcu::Vec4 positionNdc;
46 };
47
48 struct VertexDataNdcScreen
49 {
VertexDataNdcScreenvkt::pipeline::multisample::VertexDataNdcScreen50 VertexDataNdcScreen (const tcu::Vec4& posNdc, const tcu::Vec2& posScreen) : positionNdc(posNdc), positionScreen(posScreen) {}
51
52 tcu::Vec4 positionNdc;
53 tcu::Vec2 positionScreen;
54 };
55
56 struct VertexDataNdcBarycentric
57 {
VertexDataNdcBarycentricvkt::pipeline::multisample::VertexDataNdcBarycentric58 VertexDataNdcBarycentric (const tcu::Vec4& posNdc, const tcu::Vec3& barCoord) : positionNdc(posNdc), barycentricCoord(barCoord) {}
59
60 tcu::Vec4 positionNdc;
61 tcu::Vec3 barycentricCoord;
62 };
63
checkForError(const vk::VkImageCreateInfo & imageRSInfo,const tcu::ConstPixelBufferAccess & dataRS,const deUint32 errorCompNdx)64 bool checkForError (const vk::VkImageCreateInfo& imageRSInfo, const tcu::ConstPixelBufferAccess& dataRS, const deUint32 errorCompNdx)
65 {
66 for (deUint32 z = 0u; z < imageRSInfo.extent.depth; ++z)
67 for (deUint32 y = 0u; y < imageRSInfo.extent.height; ++y)
68 for (deUint32 x = 0u; x < imageRSInfo.extent.width; ++x)
69 {
70 const deUint32 errorComponent = dataRS.getPixelUint(x, y, z)[errorCompNdx];
71
72 if (errorComponent > 0)
73 return true;
74 }
75
76 return false;
77 }
78
79 template <typename CaseClassName>
80 class MSCase : public MultisampleCaseBase
81 {
82 public:
MSCase(tcu::TestContext & testCtx,const std::string & name,const ImageMSParams & imageMSParams)83 MSCase (tcu::TestContext& testCtx,
84 const std::string& name,
85 const ImageMSParams& imageMSParams)
86 : MultisampleCaseBase(testCtx, name, imageMSParams) {}
87
88 void init (void);
89 void initPrograms (vk::SourceCollections& programCollection) const;
90 TestInstance* createInstance (Context& context) const;
91 static MultisampleCaseBase* createCase (tcu::TestContext& testCtx,
92 const std::string& name,
93 const ImageMSParams& imageMSParams);
94 };
95
96 template <typename CaseClassName>
createCase(tcu::TestContext & testCtx,const std::string & name,const ImageMSParams & imageMSParams)97 MultisampleCaseBase* MSCase<CaseClassName>::createCase (tcu::TestContext& testCtx, const std::string& name, const ImageMSParams& imageMSParams)
98 {
99 return new MSCase<CaseClassName>(testCtx, name, imageMSParams);
100 }
101
102 template <typename InstanceClassName>
103 class MSInstance : public MSInstanceBaseResolve
104 {
105 public:
MSInstance(Context & context,const ImageMSParams & imageMSParams)106 MSInstance (Context& context,
107 const ImageMSParams& imageMSParams)
108 : MSInstanceBaseResolve(context, imageMSParams) {}
109
110 VertexDataDesc getVertexDataDescripton (void) const;
111 void uploadVertexData (const Allocation& vertexBufferAllocation,
112 const VertexDataDesc& vertexDataDescripton) const;
113 tcu::TestStatus verifyImageData (const vk::VkImageCreateInfo& imageRSInfo,
114 const tcu::ConstPixelBufferAccess& dataRS) const;
115 };
116
117 class MSInstanceDistinctValues;
118
getVertexDataDescripton(void) const119 template<> MultisampleInstanceBase::VertexDataDesc MSInstance<MSInstanceDistinctValues>::getVertexDataDescripton (void) const
120 {
121 VertexDataDesc vertexDataDesc;
122
123 vertexDataDesc.verticesCount = 3u;
124 vertexDataDesc.dataStride = sizeof(VertexDataNdc);
125 vertexDataDesc.dataSize = vertexDataDesc.verticesCount * vertexDataDesc.dataStride;
126 vertexDataDesc.primitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
127
128 const VkVertexInputAttributeDescription vertexAttribPositionNdc =
129 {
130 0u, // deUint32 location;
131 0u, // deUint32 binding;
132 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
133 DE_OFFSET_OF(VertexDataNdc, positionNdc), // deUint32 offset;
134 };
135
136 vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionNdc);
137
138 return vertexDataDesc;
139 }
140
uploadVertexData(const Allocation & vertexBufferAllocation,const VertexDataDesc & vertexDataDescripton) const141 template<> void MSInstance<MSInstanceDistinctValues>::uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const
142 {
143 std::vector<VertexDataNdc> vertices;
144
145 vertices.push_back(VertexDataNdc(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f)));
146 vertices.push_back(VertexDataNdc(tcu::Vec4(-1.0f, 4.0f, 0.0f, 1.0f)));
147 vertices.push_back(VertexDataNdc(tcu::Vec4( 4.0f, -1.0f, 0.0f, 1.0f)));
148
149 deMemcpy(vertexBufferAllocation.getHostPtr(), dataPointer(vertices), static_cast<std::size_t>(vertexDataDescripton.dataSize));
150 }
151
verifyImageData(const vk::VkImageCreateInfo & imageRSInfo,const tcu::ConstPixelBufferAccess & dataRS) const152 template<> tcu::TestStatus MSInstance<MSInstanceDistinctValues>::verifyImageData (const vk::VkImageCreateInfo& imageRSInfo, const tcu::ConstPixelBufferAccess& dataRS) const
153 {
154 const deUint32 distinctValuesExpected = static_cast<deUint32>(m_imageMSParams.numSamples) + 1u;
155
156 std::vector<tcu::IVec4> distinctValues;
157
158 for (deUint32 z = 0u; z < imageRSInfo.extent.depth; ++z)
159 for (deUint32 y = 0u; y < imageRSInfo.extent.height; ++y)
160 for (deUint32 x = 0u; x < imageRSInfo.extent.width; ++x)
161 {
162 const tcu::IVec4 pixel = dataRS.getPixelInt(x, y, z);
163
164 if (std::find(distinctValues.begin(), distinctValues.end(), pixel) == distinctValues.end())
165 distinctValues.push_back(pixel);
166 }
167
168 if (distinctValues.size() >= distinctValuesExpected)
169 return tcu::TestStatus::pass("Passed");
170 else
171 return tcu::TestStatus::fail("Expected numSamples+1 different colors in the output image");
172 }
173
174 class MSCaseSampleQualifierDistinctValues;
175
init(void)176 template<> void MSCase<MSCaseSampleQualifierDistinctValues>::init (void)
177 {
178 m_testCtx.getLog()
179 << tcu::TestLog::Message
180 << "Verifying that a sample qualified varying is given different values for different samples.\n"
181 << " Render full screen traingle with quadratic function defining red/green color pattern division.\n"
182 << " => Resulting image should contain n+1 different colors, where n = sample count.\n"
183 << tcu::TestLog::EndMessage;
184
185 MultisampleCaseBase::init();
186 }
187
initPrograms(vk::SourceCollections & programCollection) const188 template<> void MSCase<MSCaseSampleQualifierDistinctValues>::initPrograms (vk::SourceCollections& programCollection) const
189 {
190 // Create vertex shader
191 std::ostringstream vs;
192
193 vs << "#version 440\n"
194 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
195 << "\n"
196 << "layout(location = 0) out vec4 vs_out_position_ndc;\n"
197 << "\n"
198 << "out gl_PerVertex {\n"
199 << " vec4 gl_Position;\n"
200 << "};\n"
201 << "void main (void)\n"
202 << "{\n"
203 << " gl_Position = vs_in_position_ndc;\n"
204 << " vs_out_position_ndc = vs_in_position_ndc;\n"
205 << "}\n";
206
207 programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
208
209 // Create fragment shader
210 std::ostringstream fs;
211
212 fs << "#version 440\n"
213 << "layout(location = 0) sample in vec4 fs_in_position_ndc;\n"
214 << "\n"
215 << "layout(location = 0) out vec4 fs_out_color;\n"
216 << "\n"
217 << "void main (void)\n"
218 << "{\n"
219 << " if(fs_in_position_ndc.y < -2.0*pow(0.5*(fs_in_position_ndc.x + 1.0), 2.0) + 1.0)\n"
220 << " fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
221 << " else\n"
222 << " fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
223 << "}\n";
224
225 programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
226 }
227
createInstance(Context & context) const228 template<> TestInstance* MSCase<MSCaseSampleQualifierDistinctValues>::createInstance (Context& context) const
229 {
230 if (!context.getDeviceFeatures().sampleRateShading)
231 TCU_THROW(NotSupportedError, "sampleRateShading support required");
232 return new MSInstance<MSInstanceDistinctValues>(context, m_imageMSParams);
233 }
234
235 class MSCaseInterpolateAtSampleDistinctValues;
236
init(void)237 template<> void MSCase<MSCaseInterpolateAtSampleDistinctValues>::init (void)
238 {
239 m_testCtx.getLog()
240 << tcu::TestLog::Message
241 << "Verifying that a interpolateAtSample returns different values for different samples.\n"
242 << " Render full screen traingle with quadratic function defining red/green color pattern division.\n"
243 << " => Resulting image should contain n+1 different colors, where n = sample count.\n"
244 << tcu::TestLog::EndMessage;
245
246 MultisampleCaseBase::init();
247 }
248
initPrograms(vk::SourceCollections & programCollection) const249 template<> void MSCase<MSCaseInterpolateAtSampleDistinctValues>::initPrograms (vk::SourceCollections& programCollection) const
250 {
251 // Create vertex shader
252 std::ostringstream vs;
253
254 vs << "#version 440\n"
255 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
256 << "\n"
257 << "layout(location = 0) out vec4 vs_out_position_ndc;\n"
258 << "\n"
259 << "out gl_PerVertex {\n"
260 << " vec4 gl_Position;\n"
261 << "};\n"
262 << "void main (void)\n"
263 << "{\n"
264 << " gl_Position = vs_in_position_ndc;\n"
265 << " vs_out_position_ndc = vs_in_position_ndc;\n"
266 << "}\n";
267
268 programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
269
270 // Create fragment shader
271 std::ostringstream fs;
272
273 fs << "#version 440\n"
274 << "layout(location = 0) in vec4 fs_in_position_ndc;\n"
275 << "\n"
276 << "layout(location = 0) out vec4 fs_out_color;\n"
277 << "\n"
278 << "void main (void)\n"
279 << "{\n"
280 << " const vec4 position_ndc_at_sample = interpolateAtSample(fs_in_position_ndc, gl_SampleID);\n"
281 << " if(position_ndc_at_sample.y < -2.0*pow(0.5*(position_ndc_at_sample.x + 1.0), 2.0) + 1.0)\n"
282 << " fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
283 << " else\n"
284 << " fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
285 << "}\n";
286
287 programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
288 }
289
createInstance(Context & context) const290 template<> TestInstance* MSCase<MSCaseInterpolateAtSampleDistinctValues>::createInstance (Context& context) const
291 {
292 if (!context.getDeviceFeatures().sampleRateShading)
293 TCU_THROW(NotSupportedError, "sampleRateShading support required");
294
295 return new MSInstance<MSInstanceDistinctValues>(context, m_imageMSParams);
296 }
297
298 class MSInstanceInterpolateScreenPosition;
299
getVertexDataDescripton(void) const300 template<> MSInstanceBaseResolve::VertexDataDesc MSInstance<MSInstanceInterpolateScreenPosition>::getVertexDataDescripton (void) const
301 {
302 VertexDataDesc vertexDataDesc;
303
304 vertexDataDesc.verticesCount = 4u;
305 vertexDataDesc.dataStride = sizeof(VertexDataNdcScreen);
306 vertexDataDesc.dataSize = vertexDataDesc.verticesCount * vertexDataDesc.dataStride;
307 vertexDataDesc.primitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
308
309 const VkVertexInputAttributeDescription vertexAttribPositionNdc =
310 {
311 0u, // deUint32 location;
312 0u, // deUint32 binding;
313 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
314 DE_OFFSET_OF(VertexDataNdcScreen, positionNdc), // deUint32 offset;
315 };
316
317 vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionNdc);
318
319 const VkVertexInputAttributeDescription vertexAttribPositionScreen =
320 {
321 1u, // deUint32 location;
322 0u, // deUint32 binding;
323 VK_FORMAT_R32G32_SFLOAT, // VkFormat format;
324 DE_OFFSET_OF(VertexDataNdcScreen, positionScreen), // deUint32 offset;
325 };
326
327 vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionScreen);
328
329 return vertexDataDesc;
330 }
331
uploadVertexData(const Allocation & vertexBufferAllocation,const VertexDataDesc & vertexDataDescripton) const332 template<> void MSInstance<MSInstanceInterpolateScreenPosition>::uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const
333 {
334 const tcu::UVec3 layerSize = getLayerSize(IMAGE_TYPE_2D, m_imageMSParams.imageSize);
335 const float screenSizeX = static_cast<float>(layerSize.x());
336 const float screenSizeY = static_cast<float>(layerSize.y());
337
338 std::vector<VertexDataNdcScreen> vertices;
339
340 vertices.push_back(VertexDataNdcScreen(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec2(0.0f, 0.0f)));
341 vertices.push_back(VertexDataNdcScreen(tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec2(screenSizeX, 0.0f)));
342 vertices.push_back(VertexDataNdcScreen(tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f), tcu::Vec2(0.0f, screenSizeY)));
343 vertices.push_back(VertexDataNdcScreen(tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f), tcu::Vec2(screenSizeX, screenSizeY)));
344
345 deMemcpy(vertexBufferAllocation.getHostPtr(), dataPointer(vertices), static_cast<std::size_t>(vertexDataDescripton.dataSize));
346 }
347
verifyImageData(const vk::VkImageCreateInfo & imageRSInfo,const tcu::ConstPixelBufferAccess & dataRS) const348 template<> tcu::TestStatus MSInstance<MSInstanceInterpolateScreenPosition>::verifyImageData (const vk::VkImageCreateInfo& imageRSInfo, const tcu::ConstPixelBufferAccess& dataRS) const
349 {
350 if (checkForError(imageRSInfo, dataRS, 0))
351 return tcu::TestStatus::fail("Failed");
352
353 return tcu::TestStatus::pass("Passed");
354 }
355
356 class MSCaseInterpolateAtSampleSingleSample;
357
init(void)358 template<> void MSCase<MSCaseInterpolateAtSampleSingleSample>::init (void)
359 {
360 m_testCtx.getLog()
361 << tcu::TestLog::Message
362 << "Verifying that using interpolateAtSample with multisample buffers not available returns sample evaluated at the center of the pixel.\n"
363 << " Interpolate varying containing screen space location.\n"
364 << " => fract(screen space location) should be (about) (0.5, 0.5)\n"
365 << tcu::TestLog::EndMessage;
366
367 MultisampleCaseBase::init();
368 }
369
initPrograms(vk::SourceCollections & programCollection) const370 template<> void MSCase<MSCaseInterpolateAtSampleSingleSample>::initPrograms (vk::SourceCollections& programCollection) const
371 {
372 // Create vertex shader
373 std::ostringstream vs;
374
375 vs << "#version 440\n"
376 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
377 << "layout(location = 1) in vec2 vs_in_position_screen;\n"
378 << "\n"
379 << "layout(location = 0) out vec2 vs_out_position_screen;\n"
380 << "\n"
381 << "out gl_PerVertex {\n"
382 << " vec4 gl_Position;\n"
383 << "};\n"
384 << "void main (void)\n"
385 << "{\n"
386 << " gl_Position = vs_in_position_ndc;\n"
387 << " vs_out_position_screen = vs_in_position_screen;\n"
388 << "}\n";
389
390 programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
391
392 // Create fragment shader
393 std::ostringstream fs;
394
395 fs << "#version 440\n"
396 << "layout(location = 0) in vec2 fs_in_position_screen;\n"
397 << "\n"
398 << "layout(location = 0) out vec4 fs_out_color;\n"
399 << "\n"
400 << "void main (void)\n"
401 << "{\n"
402 << " const float threshold = 0.15625;\n"
403 << " const vec2 position_screen_at_sample = interpolateAtSample(fs_in_position_screen, 0);\n"
404 << " const vec2 position_inside_pixel = fract(position_screen_at_sample);\n"
405 << "\n"
406 << " if (abs(position_inside_pixel.x - 0.5) <= threshold && abs(position_inside_pixel.y - 0.5) <= threshold)\n"
407 << " fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
408 << " else\n"
409 << " fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
410 << "}\n";
411
412 programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
413 }
414
createInstance(Context & context) const415 template<> TestInstance* MSCase<MSCaseInterpolateAtSampleSingleSample>::createInstance (Context& context) const
416 {
417 if (!context.getDeviceFeatures().sampleRateShading)
418 TCU_THROW(NotSupportedError, "sampleRateShading support required");
419
420 return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
421 }
422
423 class MSCaseInterpolateAtSampleIgnoresCentroid;
424
init(void)425 template<> void MSCase<MSCaseInterpolateAtSampleIgnoresCentroid>::init (void)
426 {
427 m_testCtx.getLog()
428 << tcu::TestLog::Message
429 << "Verifying that interpolateAtSample ignores centroid qualifier.\n"
430 << " Interpolate varying containing screen space location with centroid and sample qualifiers.\n"
431 << " => interpolateAtSample(screenSample, n) ~= interpolateAtSample(screenCentroid, n)\n"
432 << tcu::TestLog::EndMessage;
433
434 MultisampleCaseBase::init();
435 }
436
initPrograms(vk::SourceCollections & programCollection) const437 template<> void MSCase<MSCaseInterpolateAtSampleIgnoresCentroid>::initPrograms (vk::SourceCollections& programCollection) const
438 {
439 // Create vertex shader
440 std::ostringstream vs;
441
442 vs << "#version 440\n"
443 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
444 << "layout(location = 1) in vec2 vs_in_position_screen;\n"
445 << "\n"
446 << "layout(location = 0) out vec2 vs_out_pos_screen_centroid;\n"
447 << "layout(location = 1) out vec2 vs_out_pos_screen_fragment;\n"
448 << "\n"
449 << "out gl_PerVertex {\n"
450 << " vec4 gl_Position;\n"
451 << "};\n"
452 << "void main (void)\n"
453 << "{\n"
454 << " gl_Position = vs_in_position_ndc;\n"
455 << " vs_out_pos_screen_centroid = vs_in_position_screen;\n"
456 << " vs_out_pos_screen_fragment = vs_in_position_screen;\n"
457 << "}\n";
458
459 programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
460
461 // Create fragment shader
462 std::ostringstream fs;
463
464 fs << "#version 440\n"
465 << "layout(location = 0) centroid in vec2 fs_in_pos_screen_centroid;\n"
466 << "layout(location = 1) in vec2 fs_in_pos_screen_fragment;\n"
467 << "\n"
468 << "layout(location = 0) out vec4 fs_out_color;\n"
469 << "\n"
470 << "void main (void)\n"
471 << "{\n"
472 << " const float threshold = 0.0005;\n"
473 << "\n"
474 << " const vec2 position_a = interpolateAtSample(fs_in_pos_screen_centroid, gl_SampleID);\n"
475 << " const vec2 position_b = interpolateAtSample(fs_in_pos_screen_fragment, gl_SampleID);\n"
476 << " const bool valuesEqual = all(lessThan(abs(position_a - position_b), vec2(threshold)));\n"
477 << "\n"
478 << " if (valuesEqual)\n"
479 << " fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
480 << " else\n"
481 << " fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
482 << "}\n";
483
484 programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
485 }
486
createInstance(Context & context) const487 template<> TestInstance* MSCase<MSCaseInterpolateAtSampleIgnoresCentroid>::createInstance (Context& context) const
488 {
489 if (!context.getDeviceFeatures().sampleRateShading)
490 TCU_THROW(NotSupportedError, "sampleRateShading support required");
491
492 return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
493 }
494
495 class MSCaseInterpolateAtSampleConsistency;
496
init(void)497 template<> void MSCase<MSCaseInterpolateAtSampleConsistency>::init (void)
498 {
499 m_testCtx.getLog()
500 << tcu::TestLog::Message
501 << "Verifying that interpolateAtSample with the sample set to the current sampleID returns consistent values.\n"
502 << " Interpolate varying containing screen space location with centroid and sample qualifiers.\n"
503 << " => interpolateAtSample(screenCentroid, sampleID) = screenSample\n"
504 << tcu::TestLog::EndMessage;
505
506 MultisampleCaseBase::init();
507 }
508
initPrograms(vk::SourceCollections & programCollection) const509 template<> void MSCase<MSCaseInterpolateAtSampleConsistency>::initPrograms (vk::SourceCollections& programCollection) const
510 {
511 // Create vertex shader
512 std::ostringstream vs;
513
514 vs << "#version 440\n"
515 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
516 << "layout(location = 1) in vec2 vs_in_position_screen;\n"
517 << "\n"
518 << "layout(location = 0) out vec2 vs_out_pos_screen_centroid;\n"
519 << "layout(location = 1) out vec2 vs_out_pos_screen_sample;\n"
520 << "\n"
521 << "out gl_PerVertex {\n"
522 << " vec4 gl_Position;\n"
523 << "};\n"
524 << "void main (void)\n"
525 << "{\n"
526 << " gl_Position = vs_in_position_ndc;\n"
527 << " vs_out_pos_screen_centroid = vs_in_position_screen;\n"
528 << " vs_out_pos_screen_sample = vs_in_position_screen;\n"
529 << "}\n";
530
531 programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
532
533 // Create fragment shader
534 std::ostringstream fs;
535
536 fs << "#version 440\n"
537 << "layout(location = 0) centroid in vec2 fs_in_pos_screen_centroid;\n"
538 << "layout(location = 1) sample in vec2 fs_in_pos_screen_sample;\n"
539 << "\n"
540 << "layout(location = 0) out vec4 fs_out_color;\n"
541 << "\n"
542 << "void main (void)\n"
543 << "{\n"
544 << " const float threshold = 0.15625;\n"
545 << "\n"
546 << " const vec2 pos_interpolated_at_sample = interpolateAtSample(fs_in_pos_screen_centroid, gl_SampleID);\n"
547 << " const bool valuesEqual = all(lessThan(abs(pos_interpolated_at_sample - fs_in_pos_screen_sample), vec2(threshold)));\n"
548 << "\n"
549 << " if (valuesEqual)\n"
550 << " fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
551 << " else\n"
552 << " fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
553 << "}\n";
554
555 programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
556 }
557
createInstance(Context & context) const558 template<> TestInstance* MSCase<MSCaseInterpolateAtSampleConsistency>::createInstance (Context& context) const
559 {
560 if (!context.getDeviceFeatures().sampleRateShading)
561 TCU_THROW(NotSupportedError, "sampleRateShading support required");
562
563 return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
564 }
565
566 class MSCaseInterpolateAtCentroidConsistency;
567
init(void)568 template<> void MSCase<MSCaseInterpolateAtCentroidConsistency>::init (void)
569 {
570 m_testCtx.getLog()
571 << tcu::TestLog::Message
572 << "Verifying that interpolateAtCentroid does not return different values than a corresponding centroid qualified varying.\n"
573 << " Interpolate varying containing screen space location with sample and centroid qualifiers.\n"
574 << " => interpolateAtCentroid(screenSample) = screenCentroid\n"
575 << tcu::TestLog::EndMessage;
576
577 MultisampleCaseBase::init();
578 }
579
initPrograms(vk::SourceCollections & programCollection) const580 template<> void MSCase<MSCaseInterpolateAtCentroidConsistency>::initPrograms (vk::SourceCollections& programCollection) const
581 {
582 // Create vertex shader
583 std::ostringstream vs;
584
585 vs << "#version 440\n"
586 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
587 << "layout(location = 1) in vec2 vs_in_position_screen;\n"
588 << "\n"
589 << "layout(location = 0) out vec2 vs_out_pos_screen_sample;\n"
590 << "layout(location = 1) out vec2 vs_out_pos_screen_centroid;\n"
591 << "\n"
592 << "out gl_PerVertex {\n"
593 << " vec4 gl_Position;\n"
594 << "};\n"
595 << "void main (void)\n"
596 << "{\n"
597 << " gl_Position = vs_in_position_ndc;\n"
598 << " vs_out_pos_screen_sample = vs_in_position_screen;\n"
599 << " vs_out_pos_screen_centroid = vs_in_position_screen;\n"
600 << "}\n";
601
602 programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
603
604 // Create fragment shader
605 std::ostringstream fs;
606
607 fs << "#version 440\n"
608 << "layout(location = 0) sample in vec2 fs_in_pos_screen_sample;\n"
609 << "layout(location = 1) centroid in vec2 fs_in_pos_screen_centroid;\n"
610 << "\n"
611 << "layout(location = 0) out vec4 fs_out_color;\n"
612 << "\n"
613 << "void main (void)\n"
614 << "{\n"
615 << " const float threshold = 0.0005;\n"
616 << "\n"
617 << " const vec2 pos_interpolated_at_centroid = interpolateAtCentroid(fs_in_pos_screen_sample);\n"
618 << " const bool valuesEqual = all(lessThan(abs(pos_interpolated_at_centroid - fs_in_pos_screen_centroid), vec2(threshold)));\n"
619 << "\n"
620 << " if (valuesEqual)\n"
621 << " fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
622 << " else\n"
623 << " fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
624 << "}\n";
625
626 programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
627 }
628
createInstance(Context & context) const629 template<> TestInstance* MSCase<MSCaseInterpolateAtCentroidConsistency>::createInstance (Context& context) const
630 {
631 if (!context.getDeviceFeatures().sampleRateShading)
632 TCU_THROW(NotSupportedError, "sampleRateShading support required");
633
634 return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
635 }
636
637 class MSCaseInterpolateAtOffsetPixelCenter;
638
init(void)639 template<> void MSCase<MSCaseInterpolateAtOffsetPixelCenter>::init (void)
640 {
641 m_testCtx.getLog()
642 << tcu::TestLog::Message
643 << "Verifying that interpolateAtOffset returns value sampled at an offset from the center of the pixel.\n"
644 << " Interpolate varying containing screen space location.\n"
645 << " => interpolateAtOffset(screen, offset) should be \"varying value at the pixel center\" + offset"
646 << tcu::TestLog::EndMessage;
647
648 MultisampleCaseBase::init();
649 }
650
initPrograms(vk::SourceCollections & programCollection) const651 template<> void MSCase<MSCaseInterpolateAtOffsetPixelCenter>::initPrograms (vk::SourceCollections& programCollection) const
652 {
653 // Create vertex shader
654 std::ostringstream vs;
655
656 vs << "#version 440\n"
657 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
658 << "layout(location = 1) in vec2 vs_in_position_screen;\n"
659 << "\n"
660 << "layout(location = 0) out vec2 vs_out_pos_screen;\n"
661 << "layout(location = 1) out vec2 vs_out_offset;\n"
662 << "\n"
663 << "out gl_PerVertex {\n"
664 << " vec4 gl_Position;\n"
665 << "};\n"
666 << "void main (void)\n"
667 << "{\n"
668 << " gl_Position = vs_in_position_ndc;\n"
669 << " vs_out_pos_screen = vs_in_position_screen;\n"
670 << " vs_out_offset = vs_in_position_ndc.xy * 0.5;\n"
671 << "}\n";
672
673 programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
674
675 // Create fragment shader
676 std::ostringstream fs;
677
678 fs << "#version 440\n"
679 << "layout(location = 0) in vec2 fs_in_pos_screen;\n"
680 << "layout(location = 1) in vec2 fs_in_offset;\n"
681 << "\n"
682 << "layout(location = 0) out vec4 fs_out_color;\n"
683 << "\n"
684 << "void main (void)\n"
685 << "{\n"
686 << " const vec2 frag_center = interpolateAtOffset(fs_in_pos_screen, vec2(0.0));\n"
687 << " const vec2 center_diff = abs(frag_center - fs_in_pos_screen);\n"
688 << " const float threshold = 0.125;\n"
689 << " bool valuesEqual = false;\n"
690 << "\n"
691 << " if (all(lessThan(center_diff, vec2(0.5 + threshold)))) {\n"
692 << " const vec2 pos_interpolated_at_offset = interpolateAtOffset(fs_in_pos_screen, fs_in_offset);\n"
693 << " const vec2 reference_value = frag_center + fs_in_offset;\n"
694 << "\n"
695 << " valuesEqual = all(lessThan(abs(pos_interpolated_at_offset - reference_value), vec2(threshold)));\n"
696 << " }\n"
697 << "\n"
698 << " if (valuesEqual)\n"
699 << " fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
700 << " else\n"
701 << " fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
702 << "}\n";
703
704 programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
705 }
706
createInstance(Context & context) const707 template<> TestInstance* MSCase<MSCaseInterpolateAtOffsetPixelCenter>::createInstance (Context& context) const
708 {
709 if (!context.getDeviceFeatures().sampleRateShading)
710 TCU_THROW(NotSupportedError, "sampleRateShading support required");
711
712 return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
713 }
714
715 class MSCaseInterpolateAtOffsetSamplePosition;
716
init(void)717 template<> void MSCase<MSCaseInterpolateAtOffsetSamplePosition>::init (void)
718 {
719 m_testCtx.getLog()
720 << tcu::TestLog::Message
721 << "Verifying that interpolateAtOffset of screen position with the offset of current sample position returns value "
722 << "similar to screen position interpolated at sample.\n"
723 << " Interpolate varying containing screen space location with and without sample qualifier.\n"
724 << " => interpolateAtOffset(screenFragment, samplePosition - (0.5,0.5)) = screenSample"
725 << tcu::TestLog::EndMessage;
726
727 MultisampleCaseBase::init();
728 }
729
initPrograms(vk::SourceCollections & programCollection) const730 template<> void MSCase<MSCaseInterpolateAtOffsetSamplePosition>::initPrograms (vk::SourceCollections& programCollection) const
731 {
732 // Create vertex shader
733 std::ostringstream vs;
734
735 vs << "#version 440\n"
736 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
737 << "layout(location = 1) in vec2 vs_in_position_screen;\n"
738 << "\n"
739 << "layout(location = 0) out vec2 vs_out_pos_screen_fragment;\n"
740 << "layout(location = 1) out vec2 vs_out_pos_screen_sample;\n"
741 << "\n"
742 << "out gl_PerVertex {\n"
743 << " vec4 gl_Position;\n"
744 << "};\n"
745 << "void main (void)\n"
746 << "{\n"
747 << " gl_Position = vs_in_position_ndc;\n"
748 << " vs_out_pos_screen_fragment = vs_in_position_screen;\n"
749 << " vs_out_pos_screen_sample = vs_in_position_screen;\n"
750 << "}\n";
751
752 programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
753
754 // Create fragment shader
755 std::ostringstream fs;
756
757 fs << "#version 440\n"
758 << "layout(location = 0) in vec2 fs_in_pos_screen_fragment;\n"
759 << "layout(location = 1) sample in vec2 fs_in_pos_screen_sample;\n"
760 << "\n"
761 << "layout(location = 0) out vec4 fs_out_color;\n"
762 << "\n"
763 << "void main (void)\n"
764 << "{\n"
765 << " const float threshold = 0.15625;\n"
766 << "\n"
767 << " const vec2 offset = gl_SamplePosition - vec2(0.5, 0.5);\n"
768 << " const vec2 pos_interpolated_at_offset = interpolateAtOffset(fs_in_pos_screen_fragment, offset);\n"
769 << " const bool valuesEqual = all(lessThan(abs(pos_interpolated_at_offset - fs_in_pos_screen_sample), vec2(threshold)));\n"
770 << "\n"
771 << " if (valuesEqual)\n"
772 << " fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
773 << " else\n"
774 << " fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
775 << "}\n";
776
777 programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
778 }
779
createInstance(Context & context) const780 template<> TestInstance* MSCase<MSCaseInterpolateAtOffsetSamplePosition>::createInstance (Context& context) const
781 {
782 if (!context.getDeviceFeatures().sampleRateShading)
783 TCU_THROW(NotSupportedError, "sampleRateShading support required");
784
785 return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
786 }
787
788 class MSInstanceInterpolateBarycentricCoordinates;
789
getVertexDataDescripton(void) const790 template<> MSInstanceBaseResolve::VertexDataDesc MSInstance<MSInstanceInterpolateBarycentricCoordinates>::getVertexDataDescripton (void) const
791 {
792 VertexDataDesc vertexDataDesc;
793
794 vertexDataDesc.verticesCount = 3u;
795 vertexDataDesc.dataStride = sizeof(VertexDataNdcBarycentric);
796 vertexDataDesc.dataSize = vertexDataDesc.verticesCount * vertexDataDesc.dataStride;
797 vertexDataDesc.primitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
798
799 const VkVertexInputAttributeDescription vertexAttribPositionNdc =
800 {
801 0u, // deUint32 location;
802 0u, // deUint32 binding;
803 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
804 DE_OFFSET_OF(VertexDataNdcBarycentric, positionNdc), // deUint32 offset;
805 };
806
807 vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionNdc);
808
809 const VkVertexInputAttributeDescription vertexAttrBarCoord =
810 {
811 1u, // deUint32 location;
812 0u, // deUint32 binding;
813 VK_FORMAT_R32G32B32_SFLOAT, // VkFormat format;
814 DE_OFFSET_OF(VertexDataNdcBarycentric, barycentricCoord), // deUint32 offset;
815 };
816
817 vertexDataDesc.vertexAttribDescVec.push_back(vertexAttrBarCoord);
818
819 return vertexDataDesc;
820 }
821
uploadVertexData(const Allocation & vertexBufferAllocation,const VertexDataDesc & vertexDataDescripton) const822 template<> void MSInstance<MSInstanceInterpolateBarycentricCoordinates>::uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const
823 {
824 // Create buffer storing vertex data
825 std::vector<VertexDataNdcBarycentric> vertices;
826
827 vertices.push_back(VertexDataNdcBarycentric(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec3(0.0f, 0.0f, 1.0f)));
828 vertices.push_back(VertexDataNdcBarycentric(tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f), tcu::Vec3(1.0f, 0.0f, 0.0f)));
829 vertices.push_back(VertexDataNdcBarycentric(tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec3(0.0f, 1.0f, 0.0f)));
830
831 deMemcpy(vertexBufferAllocation.getHostPtr(), dataPointer(vertices), static_cast<std::size_t>(vertexDataDescripton.dataSize));
832 }
833
verifyImageData(const vk::VkImageCreateInfo & imageRSInfo,const tcu::ConstPixelBufferAccess & dataRS) const834 template<> tcu::TestStatus MSInstance<MSInstanceInterpolateBarycentricCoordinates>::verifyImageData (const vk::VkImageCreateInfo& imageRSInfo, const tcu::ConstPixelBufferAccess& dataRS) const
835 {
836 if (checkForError(imageRSInfo, dataRS, 0))
837 return tcu::TestStatus::fail("Failed");
838
839 return tcu::TestStatus::pass("Passed");
840 }
841
842 class MSCaseCentroidQualifierInsidePrimitive;
843
init(void)844 template<> void MSCase<MSCaseCentroidQualifierInsidePrimitive>::init (void)
845 {
846 m_testCtx.getLog()
847 << tcu::TestLog::Message
848 << "Verifying that varying qualified with centroid is interpolated at location inside both the pixel and the primitive being processed.\n"
849 << " Interpolate triangle's barycentric coordinates with centroid qualifier.\n"
850 << " => After interpolation we expect barycentric.xyz >= 0.0 && barycentric.xyz <= 1.0\n"
851 << tcu::TestLog::EndMessage;
852
853 MultisampleCaseBase::init();
854 }
855
initPrograms(vk::SourceCollections & programCollection) const856 template<> void MSCase<MSCaseCentroidQualifierInsidePrimitive>::initPrograms (vk::SourceCollections& programCollection) const
857 {
858 // Create vertex shader
859 std::ostringstream vs;
860
861 vs << "#version 440\n"
862 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
863 << "layout(location = 1) in vec3 vs_in_barCoord;\n"
864 << "\n"
865 << "layout(location = 0) out vec3 vs_out_barCoord;\n"
866 << "\n"
867 << "out gl_PerVertex {\n"
868 << " vec4 gl_Position;\n"
869 << "};\n"
870 << "void main (void)\n"
871 << "{\n"
872 << " gl_Position = vs_in_position_ndc;\n"
873 << " vs_out_barCoord = vs_in_barCoord;\n"
874 << "}\n";
875
876 programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
877
878 // Create fragment shader
879 std::ostringstream fs;
880
881 fs << "#version 440\n"
882 << "layout(location = 0) centroid in vec3 fs_in_barCoord;\n"
883 << "\n"
884 << "layout(location = 0) out vec4 fs_out_color;\n"
885 << "\n"
886 << "void main (void)\n"
887 << "{\n"
888 << " if( all(greaterThanEqual(fs_in_barCoord, vec3(0.0))) && all(lessThanEqual(fs_in_barCoord, vec3(1.0))) )\n"
889 << " fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
890 << " else\n"
891 << " fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
892 << "}\n";
893
894 programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
895 }
896
createInstance(Context & context) const897 template<> TestInstance* MSCase<MSCaseCentroidQualifierInsidePrimitive>::createInstance (Context& context) const
898 {
899 return new MSInstance<MSInstanceInterpolateBarycentricCoordinates>(context, m_imageMSParams);
900 }
901
902 } // multisample
903
createMultisampleInterpolationTests(tcu::TestContext & testCtx)904 tcu::TestCaseGroup* createMultisampleInterpolationTests (tcu::TestContext& testCtx)
905 {
906 de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "multisample_interpolation", "Multisample Interpolation"));
907
908 const tcu::UVec3 imageSizes[] =
909 {
910 tcu::UVec3(128u, 128u, 1u),
911 tcu::UVec3(137u, 191u, 1u),
912 };
913
914 const deUint32 sizesElemCount = static_cast<deUint32>(sizeof(imageSizes) / sizeof(tcu::UVec3));
915
916 const vk::VkSampleCountFlagBits imageSamples[] =
917 {
918 vk::VK_SAMPLE_COUNT_2_BIT,
919 vk::VK_SAMPLE_COUNT_4_BIT,
920 vk::VK_SAMPLE_COUNT_8_BIT,
921 vk::VK_SAMPLE_COUNT_16_BIT,
922 vk::VK_SAMPLE_COUNT_32_BIT,
923 vk::VK_SAMPLE_COUNT_64_BIT,
924 };
925
926 const deUint32 samplesElemCount = static_cast<deUint32>(sizeof(imageSamples) / sizeof(vk::VkSampleCountFlagBits));
927
928 de::MovePtr<tcu::TestCaseGroup> caseGroup(new tcu::TestCaseGroup(testCtx, "sample_interpolate_at_single_sample", ""));
929
930 for (deUint32 imageSizeNdx = 0u; imageSizeNdx < sizesElemCount; ++imageSizeNdx)
931 {
932 const tcu::UVec3 imageSize = imageSizes[imageSizeNdx];
933 std::ostringstream imageSizeStream;
934
935 imageSizeStream << imageSize.x() << "_" << imageSize.y() << "_" << imageSize.z();
936
937 de::MovePtr<tcu::TestCaseGroup> sizeGroup(new tcu::TestCaseGroup(testCtx, imageSizeStream.str().c_str(), ""));
938
939 sizeGroup->addChild(multisample::MSCase<multisample::MSCaseInterpolateAtSampleSingleSample>::createCase(testCtx, "samples_" + de::toString(1), multisample::ImageMSParams(vk::VK_SAMPLE_COUNT_1_BIT, imageSize)));
940
941 caseGroup->addChild(sizeGroup.release());
942 }
943
944 testGroup->addChild(caseGroup.release());
945
946 testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtSampleDistinctValues> > (testCtx, "sample_interpolate_at_distinct_values", imageSizes, sizesElemCount, imageSamples, samplesElemCount));
947 testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtSampleIgnoresCentroid> >(testCtx, "sample_interpolate_at_ignores_centroid", imageSizes, sizesElemCount, imageSamples, samplesElemCount));
948 testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtSampleConsistency> > (testCtx, "sample_interpolate_at_consistency", imageSizes, sizesElemCount, imageSamples, samplesElemCount));
949 testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseSampleQualifierDistinctValues> > (testCtx, "sample_qualifier_distinct_values", imageSizes, sizesElemCount, imageSamples, samplesElemCount));
950 testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtCentroidConsistency> > (testCtx, "centroid_interpolate_at_consistency", imageSizes, sizesElemCount, imageSamples, samplesElemCount));
951 testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseCentroidQualifierInsidePrimitive> > (testCtx, "centroid_qualifier_inside_primitive", imageSizes, sizesElemCount, imageSamples, samplesElemCount));
952 testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtOffsetPixelCenter> > (testCtx, "offset_interpolate_at_pixel_center", imageSizes, sizesElemCount, imageSamples, samplesElemCount));
953 testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtOffsetSamplePosition> > (testCtx, "offset_interpolate_at_sample_position", imageSizes, sizesElemCount, imageSamples, samplesElemCount));
954
955 return testGroup.release();
956 }
957
958 } // pipeline
959 } // vkt
960