1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2016 The Khronos Group Inc.
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 * \file vktPipelineMultisampleShaderBuiltInTests.cpp
21 * \brief Multisample Shader BuiltIn Tests
22 *//*--------------------------------------------------------------------*/
24 #include "vktPipelineMultisampleShaderBuiltInTests.hpp"
25 #include "vktPipelineMultisampleBaseResolveAndPerSampleFetch.hpp"
26 #include "vktPipelineMakeUtil.hpp"
27 #include "vkBuilderUtil.hpp"
28 #include "vkQueryUtil.hpp"
29 #include "tcuVectorUtil.hpp"
30 #include "tcuTestLog.hpp"
43 VertexDataNdc (const tcu::Vec4& posNdc) : positionNdc(posNdc) {}
45 tcu::Vec4 positionNdc;
48 MultisampleInstanceBase::VertexDataDesc getVertexDataDescriptonNdc (void)
50 MultisampleInstanceBase::VertexDataDesc vertexDataDesc;
52 vertexDataDesc.verticesCount = 4u;
53 vertexDataDesc.dataStride = sizeof(VertexDataNdc);
54 vertexDataDesc.dataSize = vertexDataDesc.verticesCount * vertexDataDesc.dataStride;
55 vertexDataDesc.primitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
57 const VkVertexInputAttributeDescription vertexAttribPositionNdc =
59 0u, // deUint32 location;
60 0u, // deUint32 binding;
61 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
62 DE_OFFSET_OF(VertexDataNdc, positionNdc), // deUint32 offset;
65 vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionNdc);
67 return vertexDataDesc;
70 void uploadVertexDataNdc (const Allocation& vertexBufferAllocation, const MultisampleInstanceBase::VertexDataDesc& vertexDataDescripton)
72 std::vector<VertexDataNdc> vertices;
74 vertices.push_back(VertexDataNdc(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f)));
75 vertices.push_back(VertexDataNdc(tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f)));
76 vertices.push_back(VertexDataNdc(tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f)));
77 vertices.push_back(VertexDataNdc(tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f)));
79 deMemcpy(vertexBufferAllocation.getHostPtr(), dataPointer(vertices), static_cast<std::size_t>(vertexDataDescripton.dataSize));
82 struct VertexDataNdcScreen
84 VertexDataNdcScreen (const tcu::Vec4& posNdc, const tcu::Vec2& posScreen) : positionNdc(posNdc), positionScreen(posScreen) {}
86 tcu::Vec4 positionNdc;
87 tcu::Vec2 positionScreen;
90 MultisampleInstanceBase::VertexDataDesc getVertexDataDescriptonNdcScreen (void)
92 MultisampleInstanceBase::VertexDataDesc vertexDataDesc;
94 vertexDataDesc.verticesCount = 4u;
95 vertexDataDesc.dataStride = sizeof(VertexDataNdcScreen);
96 vertexDataDesc.dataSize = vertexDataDesc.verticesCount * vertexDataDesc.dataStride;
97 vertexDataDesc.primitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
99 const VkVertexInputAttributeDescription vertexAttribPositionNdc =
101 0u, // deUint32 location;
102 0u, // deUint32 binding;
103 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
104 DE_OFFSET_OF(VertexDataNdcScreen, positionNdc), // deUint32 offset;
107 vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionNdc);
109 const VkVertexInputAttributeDescription vertexAttribPositionScreen =
111 1u, // deUint32 location;
112 0u, // deUint32 binding;
113 VK_FORMAT_R32G32_SFLOAT, // VkFormat format;
114 DE_OFFSET_OF(VertexDataNdcScreen, positionScreen), // deUint32 offset;
117 vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionScreen);
119 return vertexDataDesc;
122 void uploadVertexDataNdcScreen (const Allocation& vertexBufferAllocation, const MultisampleInstanceBase::VertexDataDesc& vertexDataDescripton, const tcu::Vec2& screenSize)
124 std::vector<VertexDataNdcScreen> vertices;
126 vertices.push_back(VertexDataNdcScreen(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec2(0.0f, 0.0f)));
127 vertices.push_back(VertexDataNdcScreen(tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec2(screenSize.x(), 0.0f)));
128 vertices.push_back(VertexDataNdcScreen(tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f), tcu::Vec2(0.0f, screenSize.y())));
129 vertices.push_back(VertexDataNdcScreen(tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f), tcu::Vec2(screenSize.x(), screenSize.y())));
131 deMemcpy(vertexBufferAllocation.getHostPtr(), dataPointer(vertices), static_cast<std::size_t>(vertexDataDescripton.dataSize));
134 bool checkForErrorMS (const vk::VkImageCreateInfo& imageMSInfo, const std::vector<tcu::ConstPixelBufferAccess>& dataPerSample, const deUint32 errorCompNdx)
136 const deUint32 numSamples = static_cast<deUint32>(imageMSInfo.samples);
138 for (deUint32 z = 0u; z < imageMSInfo.extent.depth; ++z)
139 for (deUint32 y = 0u; y < imageMSInfo.extent.height; ++y)
140 for (deUint32 x = 0u; x < imageMSInfo.extent.width; ++x)
142 for (deUint32 sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
144 const deUint32 errorComponent = dataPerSample[sampleNdx].getPixelUint(x, y, z)[errorCompNdx];
146 if (errorComponent > 0)
154 bool checkForErrorRS (const vk::VkImageCreateInfo& imageRSInfo, const tcu::ConstPixelBufferAccess& dataRS, const deUint32 errorCompNdx)
156 for (deUint32 z = 0u; z < imageRSInfo.extent.depth; ++z)
157 for (deUint32 y = 0u; y < imageRSInfo.extent.height; ++y)
158 for (deUint32 x = 0u; x < imageRSInfo.extent.width; ++x)
160 const deUint32 errorComponent = dataRS.getPixelUint(x, y, z)[errorCompNdx];
162 if (errorComponent > 0)
169 template <typename CaseClassName>
170 class MSCase : public MSCaseBaseResolveAndPerSampleFetch
173 MSCase (tcu::TestContext& testCtx,
174 const std::string& name,
175 const ImageMSParams& imageMSParams)
176 : MSCaseBaseResolveAndPerSampleFetch(testCtx, name, imageMSParams) {}
178 virtual void checkSupport (Context&) const {}
180 void initPrograms (vk::SourceCollections& programCollection) const;
181 TestInstance* createInstance (Context& context) const;
182 static MultisampleCaseBase* createCase (tcu::TestContext& testCtx,
183 const std::string& name,
184 const ImageMSParams& imageMSParams);
187 template <typename CaseClassName>
188 MultisampleCaseBase* MSCase<CaseClassName>::createCase (tcu::TestContext& testCtx, const std::string& name, const ImageMSParams& imageMSParams)
190 return new MSCase<CaseClassName>(testCtx, name, imageMSParams);
193 template <typename InstanceClassName>
194 class MSInstance : public MSInstanceBaseResolveAndPerSampleFetch
197 MSInstance (Context& context,
198 const ImageMSParams& imageMSParams)
199 : MSInstanceBaseResolveAndPerSampleFetch(context, imageMSParams) {}
201 VertexDataDesc getVertexDataDescripton (void) const;
202 void uploadVertexData (const Allocation& vertexBufferAllocation,
203 const VertexDataDesc& vertexDataDescripton) const;
205 tcu::TestStatus verifyImageData (const vk::VkImageCreateInfo& imageMSInfo,
206 const vk::VkImageCreateInfo& imageRSInfo,
207 const std::vector<tcu::ConstPixelBufferAccess>& dataPerSample,
208 const tcu::ConstPixelBufferAccess& dataRS) const;
211 class MSInstanceSampleID;
213 template<> MultisampleInstanceBase::VertexDataDesc MSInstance<MSInstanceSampleID>::getVertexDataDescripton (void) const
215 return getVertexDataDescriptonNdc();
218 template<> void MSInstance<MSInstanceSampleID>::uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const
220 uploadVertexDataNdc(vertexBufferAllocation, vertexDataDescripton);
223 template<> tcu::TestStatus MSInstance<MSInstanceSampleID>::verifyImageData (const vk::VkImageCreateInfo& imageMSInfo,
224 const vk::VkImageCreateInfo& imageRSInfo,
225 const std::vector<tcu::ConstPixelBufferAccess>& dataPerSample,
226 const tcu::ConstPixelBufferAccess& dataRS) const
228 DE_UNREF(imageRSInfo);
231 const deUint32 numSamples = static_cast<deUint32>(imageMSInfo.samples);
233 for (deUint32 sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
235 for (deUint32 z = 0u; z < imageMSInfo.extent.depth; ++z)
236 for (deUint32 y = 0u; y < imageMSInfo.extent.height; ++y)
237 for (deUint32 x = 0u; x < imageMSInfo.extent.width; ++x)
239 const deUint32 sampleID = dataPerSample[sampleNdx].getPixelUint(x, y, z).x();
241 if (sampleID != sampleNdx)
242 return tcu::TestStatus::fail("gl_SampleID does not have correct value");
246 return tcu::TestStatus::pass("Passed");
249 class MSCaseSampleID;
251 template<> void MSCase<MSCaseSampleID>::checkSupport (Context& context) const
253 if (!context.getDeviceFeatures().sampleRateShading)
254 TCU_THROW(NotSupportedError, "sampleRateShading not supported");
257 template<> void MSCase<MSCaseSampleID>::init (void)
260 << tcu::TestLog::Message
261 << "Writing gl_SampleID to the red channel of the texture and verifying texture values.\n"
262 << "Expecting value N at sample index N of a multisample texture.\n"
263 << tcu::TestLog::EndMessage;
265 MultisampleCaseBase::init();
268 template<> void MSCase<MSCaseSampleID>::initPrograms (vk::SourceCollections& programCollection) const
270 MSCaseBaseResolveAndPerSampleFetch::initPrograms(programCollection);
272 // Create vertex shader
273 std::ostringstream vs;
275 vs << "#version 440\n"
276 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
278 << "out gl_PerVertex {\n"
279 << " vec4 gl_Position;\n"
281 << "void main (void)\n"
283 << " gl_Position = vs_in_position_ndc;\n"
286 programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
288 // Create fragment shader
289 std::ostringstream fs;
291 fs << "#version 440\n"
293 << "layout(location = 0) out vec4 fs_out_color;\n"
295 << "void main (void)\n"
297 << " fs_out_color = vec4(float(gl_SampleID) / float(255), 0.0, 0.0, 1.0);\n"
300 programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
303 template<> TestInstance* MSCase<MSCaseSampleID>::createInstance (Context& context) const
305 return new MSInstance<MSInstanceSampleID>(context, m_imageMSParams);
308 class MSInstanceSamplePosDistribution;
310 template<> MultisampleInstanceBase::VertexDataDesc MSInstance<MSInstanceSamplePosDistribution>::getVertexDataDescripton (void) const
312 return getVertexDataDescriptonNdc();
315 template<> void MSInstance<MSInstanceSamplePosDistribution>::uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const
317 uploadVertexDataNdc(vertexBufferAllocation, vertexDataDescripton);
320 template<> tcu::TestStatus MSInstance<MSInstanceSamplePosDistribution>::verifyImageData (const vk::VkImageCreateInfo& imageMSInfo,
321 const vk::VkImageCreateInfo& imageRSInfo,
322 const std::vector<tcu::ConstPixelBufferAccess>& dataPerSample,
323 const tcu::ConstPixelBufferAccess& dataRS) const
325 const deUint32 numSamples = static_cast<deUint32>(imageMSInfo.samples);
327 // approximate Bates distribution as normal
328 const float variance = (1.0f / (12.0f * (float)numSamples));
329 const float standardDeviation = deFloatSqrt(variance);
331 // 95% of means of sample positions are within 2 standard deviations if
332 // they were randomly assigned. Sample patterns are expected to be more
333 // uniform than a random pattern.
334 const float distanceThreshold = 2.0f * standardDeviation;
336 for (deUint32 z = 0u; z < imageRSInfo.extent.depth; ++z)
337 for (deUint32 y = 0u; y < imageRSInfo.extent.height; ++y)
338 for (deUint32 x = 0u; x < imageRSInfo.extent.width; ++x)
340 const deUint32 errorComponent = dataRS.getPixelUint(x, y, z).z();
342 if (errorComponent > 0)
343 return tcu::TestStatus::fail("gl_SamplePosition is not within interval [0,1]");
345 if (numSamples >= VK_SAMPLE_COUNT_4_BIT)
347 const tcu::Vec2 averageSamplePos = tcu::Vec2((float)dataRS.getPixelUint(x, y, z).x() / 255.0f, (float)dataRS.getPixelUint(x, y, z).y() / 255.0f);
348 const tcu::Vec2 distanceFromCenter = tcu::abs(averageSamplePos - tcu::Vec2(0.5f, 0.5f));
350 if (distanceFromCenter.x() > distanceThreshold || distanceFromCenter.y() > distanceThreshold)
351 return tcu::TestStatus::fail("Sample positions are not uniformly distributed within the pixel");
355 for (deUint32 z = 0u; z < imageMSInfo.extent.depth; ++z)
356 for (deUint32 y = 0u; y < imageMSInfo.extent.height; ++y)
357 for (deUint32 x = 0u; x < imageMSInfo.extent.width; ++x)
359 std::vector<tcu::Vec2> samplePositions(numSamples);
361 for (deUint32 sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
363 const deUint32 errorComponent = dataPerSample[sampleNdx].getPixelUint(x, y, z).z();
365 if (errorComponent > 0)
366 return tcu::TestStatus::fail("gl_SamplePosition is not within interval [0,1]");
368 samplePositions[sampleNdx] = tcu::Vec2( (float)dataPerSample[sampleNdx].getPixelUint(x, y, z).x() / 255.0f,
369 (float)dataPerSample[sampleNdx].getPixelUint(x, y, z).y() / 255.0f);
372 for (deUint32 sampleNdxA = 0u; sampleNdxA < numSamples; ++sampleNdxA)
373 for (deUint32 sampleNdxB = sampleNdxA + 1u; sampleNdxB < numSamples; ++sampleNdxB)
375 if (samplePositions[sampleNdxA] == samplePositions[sampleNdxB])
376 return tcu::TestStatus::fail("Two samples have the same position");
379 if (numSamples >= VK_SAMPLE_COUNT_4_BIT)
381 tcu::Vec2 averageSamplePos(0.0f, 0.0f);
383 for (deUint32 sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
385 averageSamplePos.x() += samplePositions[sampleNdx].x();
386 averageSamplePos.y() += samplePositions[sampleNdx].y();
389 averageSamplePos.x() /= (float)numSamples;
390 averageSamplePos.y() /= (float)numSamples;
392 const tcu::Vec2 distanceFromCenter = tcu::abs(averageSamplePos - tcu::Vec2(0.5f, 0.5f));
394 if (distanceFromCenter.x() > distanceThreshold || distanceFromCenter.y() > distanceThreshold)
395 return tcu::TestStatus::fail("Sample positions are not uniformly distributed within the pixel");
399 return tcu::TestStatus::pass("Passed");
402 class MSCaseSamplePosDistribution;
404 template<> void MSCase<MSCaseSamplePosDistribution>::checkSupport (Context& context) const
406 if (!context.getDeviceFeatures().sampleRateShading)
407 TCU_THROW(NotSupportedError, "sampleRateShading not supported");
410 template<> void MSCase<MSCaseSamplePosDistribution>::init (void)
413 << tcu::TestLog::Message
414 << "Verifying gl_SamplePosition value with multisample targets:\n"
415 << " a) Expect legal sample position.\n"
416 << " b) Sample position is unique within the set of all sample positions of a pixel.\n"
417 << " c) Sample position distribution is uniform or almost uniform.\n"
418 << tcu::TestLog::EndMessage;
420 MultisampleCaseBase::init();
423 template<> void MSCase<MSCaseSamplePosDistribution>::initPrograms (vk::SourceCollections& programCollection) const
425 MSCaseBaseResolveAndPerSampleFetch::initPrograms(programCollection);
427 // Create vertex shader
428 std::ostringstream vs;
430 vs << "#version 440\n"
431 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
433 << "out gl_PerVertex {\n"
434 << " vec4 gl_Position;\n"
436 << "void main (void)\n"
438 << " gl_Position = vs_in_position_ndc;\n"
441 programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
443 // Create fragment shader
444 std::ostringstream fs;
446 fs << "#version 440\n"
448 << "layout(location = 0) out vec4 fs_out_color;\n"
450 << "void main (void)\n"
452 << " if (gl_SamplePosition.x < 0.0 || gl_SamplePosition.x > 1.0 || gl_SamplePosition.y < 0.0 || gl_SamplePosition.y > 1.0)\n"
453 " fs_out_color = vec4(0.0, 0.0, 1.0, 1.0);\n"
455 " fs_out_color = vec4(gl_SamplePosition.x, gl_SamplePosition.y, 0.0, 1.0);\n"
458 programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
461 template<> TestInstance* MSCase<MSCaseSamplePosDistribution>::createInstance (Context& context) const
463 return new MSInstance<MSInstanceSamplePosDistribution>(context, m_imageMSParams);
466 class MSInstanceSamplePosCorrectness;
468 template<> MultisampleInstanceBase::VertexDataDesc MSInstance<MSInstanceSamplePosCorrectness>::getVertexDataDescripton (void) const
470 return getVertexDataDescriptonNdcScreen();
473 template<> void MSInstance<MSInstanceSamplePosCorrectness>::uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const
475 const tcu::UVec3 layerSize = getLayerSize(IMAGE_TYPE_2D, m_imageMSParams.imageSize);
477 uploadVertexDataNdcScreen(vertexBufferAllocation, vertexDataDescripton, tcu::Vec2(static_cast<float>(layerSize.x()), static_cast<float>(layerSize.y())));
480 template<> tcu::TestStatus MSInstance<MSInstanceSamplePosCorrectness>::verifyImageData (const vk::VkImageCreateInfo& imageMSInfo,
481 const vk::VkImageCreateInfo& imageRSInfo,
482 const std::vector<tcu::ConstPixelBufferAccess>& dataPerSample,
483 const tcu::ConstPixelBufferAccess& dataRS) const
485 if (checkForErrorMS(imageMSInfo, dataPerSample, 0))
486 return tcu::TestStatus::fail("Varying values are not sampled at gl_SamplePosition");
488 if (checkForErrorRS(imageRSInfo, dataRS, 0))
489 return tcu::TestStatus::fail("Varying values are not sampled at gl_SamplePosition");
491 return tcu::TestStatus::pass("Passed");
494 class MSCaseSamplePosCorrectness;
496 template<> void MSCase<MSCaseSamplePosCorrectness>::checkSupport (Context& context) const
498 if (!context.getDeviceFeatures().sampleRateShading)
499 TCU_THROW(NotSupportedError, "sampleRateShading not supported");
502 template<> void MSCase<MSCaseSamplePosCorrectness>::init (void)
505 << tcu::TestLog::Message
506 << "Verifying gl_SamplePosition correctness:\n"
507 << " 1) Varying values should be sampled at the sample position.\n"
508 << " => fract(position_screen) == gl_SamplePosition\n"
509 << tcu::TestLog::EndMessage;
511 MultisampleCaseBase::init();
514 template<> void MSCase<MSCaseSamplePosCorrectness>::initPrograms (vk::SourceCollections& programCollection) const
516 MSCaseBaseResolveAndPerSampleFetch::initPrograms(programCollection);
518 // Create vertex shaders
519 std::ostringstream vs;
521 vs << "#version 440\n"
522 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
523 << "layout(location = 1) in vec2 vs_in_position_screen;\n"
525 << "layout(location = 0) sample out vec2 vs_out_position_screen;\n"
527 << "out gl_PerVertex {\n"
528 << " vec4 gl_Position;\n"
530 << "void main (void)\n"
532 << " gl_Position = vs_in_position_ndc;\n"
533 << " vs_out_position_screen = vs_in_position_screen;\n"
536 programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
538 // Create fragment shader
539 std::ostringstream fs;
541 fs << "#version 440\n"
542 << "layout(location = 0) sample in vec2 fs_in_position_screen;\n"
544 << "layout(location = 0) out vec4 fs_out_color;\n"
546 << "void main (void)\n"
548 << " const float threshold = 0.15625; // 4 subpixel bits. Assume 3 accurate bits + 0.03125 for other errors\n"
549 << " const ivec2 nearby_pixel = ivec2(floor(fs_in_position_screen));\n"
550 << " bool ok = false;\n"
552 << " // sample at edge + inaccuaries may cause us to round to any neighboring pixel\n"
553 << " // check all neighbors for any match\n"
554 << " for (int dy = -1; dy <= 1; ++dy)\n"
555 << " for (int dx = -1; dx <= 1; ++dx)\n"
557 << " ivec2 current_pixel = nearby_pixel + ivec2(dx, dy);\n"
558 << " vec2 position_inside_pixel = vec2(current_pixel) + gl_SamplePosition;\n"
559 << " vec2 position_diff = abs(position_inside_pixel - fs_in_position_screen);\n"
561 << " if (all(lessThan(position_diff, vec2(threshold))))\n"
566 << " fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
568 << " fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
571 programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
574 template<> TestInstance* MSCase<MSCaseSamplePosCorrectness>::createInstance (Context& context) const
576 return new MSInstance<MSInstanceSamplePosCorrectness>(context, m_imageMSParams);
579 class MSInstanceSampleMaskPattern : public MSInstanceBaseResolveAndPerSampleFetch
582 MSInstanceSampleMaskPattern (Context& context,
583 const ImageMSParams& imageMSParams);
585 VkPipelineMultisampleStateCreateInfo getMSStateCreateInfo (const ImageMSParams& imageMSParams) const;
587 const VkDescriptorSetLayout* createMSPassDescSetLayout (const ImageMSParams& imageMSParams);
589 const VkDescriptorSet* createMSPassDescSet (const ImageMSParams& imageMSParams,
590 const VkDescriptorSetLayout* descSetLayout);
592 VertexDataDesc getVertexDataDescripton (void) const;
594 void uploadVertexData (const Allocation& vertexBufferAllocation,
595 const VertexDataDesc& vertexDataDescripton) const;
597 tcu::TestStatus verifyImageData (const vk::VkImageCreateInfo& imageMSInfo,
598 const vk::VkImageCreateInfo& imageRSInfo,
599 const std::vector<tcu::ConstPixelBufferAccess>& dataPerSample,
600 const tcu::ConstPixelBufferAccess& dataRS) const;
603 VkSampleMask m_sampleMask;
604 Move<VkDescriptorSetLayout> m_descriptorSetLayout;
605 Move<VkDescriptorPool> m_descriptorPool;
606 Move<VkDescriptorSet> m_descriptorSet;
607 de::MovePtr<Buffer> m_buffer;
610 MSInstanceSampleMaskPattern::MSInstanceSampleMaskPattern (Context& context, const ImageMSParams& imageMSParams) : MSInstanceBaseResolveAndPerSampleFetch(context, imageMSParams)
612 m_sampleMask = 0xAAAAAAAAu & ((1u << imageMSParams.numSamples) - 1u);
615 VkPipelineMultisampleStateCreateInfo MSInstanceSampleMaskPattern::getMSStateCreateInfo (const ImageMSParams& imageMSParams) const
617 const VkPipelineMultisampleStateCreateInfo multisampleStateInfo =
619 VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
620 DE_NULL, // const void* pNext;
621 (VkPipelineMultisampleStateCreateFlags)0u, // VkPipelineMultisampleStateCreateFlags flags;
622 imageMSParams.numSamples, // VkSampleCountFlagBits rasterizationSamples;
623 VK_TRUE, // VkBool32 sampleShadingEnable;
624 1.0f, // float minSampleShading;
625 &m_sampleMask, // const VkSampleMask* pSampleMask;
626 VK_FALSE, // VkBool32 alphaToCoverageEnable;
627 VK_FALSE, // VkBool32 alphaToOneEnable;
630 return multisampleStateInfo;
633 const VkDescriptorSetLayout* MSInstanceSampleMaskPattern::createMSPassDescSetLayout (const ImageMSParams& imageMSParams)
635 DE_UNREF(imageMSParams);
637 const DeviceInterface& deviceInterface = m_context.getDeviceInterface();
638 const VkDevice device = m_context.getDevice();
640 // Create descriptor set layout
641 m_descriptorSetLayout = DescriptorSetLayoutBuilder()
642 .addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT)
643 .build(deviceInterface, device);
645 return &m_descriptorSetLayout.get();
648 const VkDescriptorSet* MSInstanceSampleMaskPattern::createMSPassDescSet (const ImageMSParams& imageMSParams, const VkDescriptorSetLayout* descSetLayout)
650 DE_UNREF(imageMSParams);
652 const DeviceInterface& deviceInterface = m_context.getDeviceInterface();
653 const VkDevice device = m_context.getDevice();
654 Allocator& allocator = m_context.getDefaultAllocator();
656 // Create descriptor pool
657 m_descriptorPool = DescriptorPoolBuilder()
658 .addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u)
659 .build(deviceInterface, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
661 // Create descriptor set
662 m_descriptorSet = makeDescriptorSet(deviceInterface, device, *m_descriptorPool, *descSetLayout);
664 const VkBufferCreateInfo bufferSampleMaskInfo = makeBufferCreateInfo(sizeof(VkSampleMask), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
666 m_buffer = de::MovePtr<Buffer>(new Buffer(deviceInterface, device, allocator, bufferSampleMaskInfo, MemoryRequirement::HostVisible));
668 deMemcpy(m_buffer->getAllocation().getHostPtr(), &m_sampleMask, sizeof(VkSampleMask));
670 flushAlloc(deviceInterface, device, m_buffer->getAllocation());
672 const VkDescriptorBufferInfo descBufferInfo = makeDescriptorBufferInfo(**m_buffer, 0u, sizeof(VkSampleMask));
674 DescriptorSetUpdateBuilder()
675 .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descBufferInfo)
676 .update(deviceInterface, device);
678 return &m_descriptorSet.get();
681 MultisampleInstanceBase::VertexDataDesc MSInstanceSampleMaskPattern::getVertexDataDescripton (void) const
683 return getVertexDataDescriptonNdc();
686 void MSInstanceSampleMaskPattern::uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const
688 uploadVertexDataNdc(vertexBufferAllocation, vertexDataDescripton);
691 tcu::TestStatus MSInstanceSampleMaskPattern::verifyImageData (const vk::VkImageCreateInfo& imageMSInfo,
692 const vk::VkImageCreateInfo& imageRSInfo,
693 const std::vector<tcu::ConstPixelBufferAccess>& dataPerSample,
694 const tcu::ConstPixelBufferAccess& dataRS) const
696 DE_UNREF(imageRSInfo);
699 if (checkForErrorMS(imageMSInfo, dataPerSample, 0))
700 return tcu::TestStatus::fail("gl_SampleMaskIn bits have not been killed by pSampleMask state");
702 return tcu::TestStatus::pass("Passed");
705 class MSCaseSampleMaskPattern;
707 template<> void MSCase<MSCaseSampleMaskPattern>::init (void)
710 << tcu::TestLog::Message
711 << "Verifying gl_SampleMaskIn value with pSampleMask state. gl_SampleMaskIn does not contain any bits set that are have been killed by pSampleMask state. Expecting:\n"
712 << "Expected result: gl_SampleMaskIn AND ~(pSampleMask) should be zero.\n"
713 << tcu::TestLog::EndMessage;
715 MultisampleCaseBase::init();
718 template<> void MSCase<MSCaseSampleMaskPattern>::initPrograms (vk::SourceCollections& programCollection) const
720 MSCaseBaseResolveAndPerSampleFetch::initPrograms(programCollection);
722 // Create vertex shader
723 std::ostringstream vs;
725 vs << "#version 440\n"
726 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
728 << "out gl_PerVertex {\n"
729 << " vec4 gl_Position;\n"
731 << "void main (void)\n"
733 << " gl_Position = vs_in_position_ndc;\n"
736 programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
738 // Create fragment shader
739 std::ostringstream fs;
741 fs << "#version 440\n"
743 << "layout(location = 0) out vec4 fs_out_color;\n"
745 << "layout(set = 0, binding = 0, std140) uniform SampleMaskBlock\n"
747 << " int sampleMaskPattern;\n"
750 << "void main (void)\n"
752 << " if ((gl_SampleMaskIn[0] & ~sampleMaskPattern) != 0)\n"
753 << " fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
755 << " fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
758 programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
761 template<> TestInstance* MSCase<MSCaseSampleMaskPattern>::createInstance (Context& context) const
763 return new MSInstanceSampleMaskPattern(context, m_imageMSParams);
766 class MSInstanceSampleMaskBitCount;
768 template<> MultisampleInstanceBase::VertexDataDesc MSInstance<MSInstanceSampleMaskBitCount>::getVertexDataDescripton (void) const
770 return getVertexDataDescriptonNdc();
773 template<> void MSInstance<MSInstanceSampleMaskBitCount>::uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const
775 uploadVertexDataNdc(vertexBufferAllocation, vertexDataDescripton);
778 template<> tcu::TestStatus MSInstance<MSInstanceSampleMaskBitCount>::verifyImageData (const vk::VkImageCreateInfo& imageMSInfo,
779 const vk::VkImageCreateInfo& imageRSInfo,
780 const std::vector<tcu::ConstPixelBufferAccess>& dataPerSample,
781 const tcu::ConstPixelBufferAccess& dataRS) const
783 DE_UNREF(imageRSInfo);
786 if (checkForErrorMS(imageMSInfo, dataPerSample, 0))
787 return tcu::TestStatus::fail("gl_SampleMaskIn has more than one bit set for some shader invocations");
789 return tcu::TestStatus::pass("Passed");
792 class MSCaseSampleMaskBitCount;
794 template<> void MSCase<MSCaseSampleMaskBitCount>::init (void)
797 << tcu::TestLog::Message
798 << "Verifying gl_SampleMaskIn.\n"
799 << " Fragment shader will be invoked numSamples times.\n"
800 << " => gl_SampleMaskIn should have only one bit set for each shader invocation.\n"
801 << tcu::TestLog::EndMessage;
803 MultisampleCaseBase::init();
806 template<> void MSCase<MSCaseSampleMaskBitCount>::initPrograms (vk::SourceCollections& programCollection) const
808 MSCaseBaseResolveAndPerSampleFetch::initPrograms(programCollection);
810 // Create vertex shader
811 std::ostringstream vs;
813 vs << "#version 440\n"
814 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
816 << "out gl_PerVertex {\n"
817 << " vec4 gl_Position;\n"
819 << "void main (void)\n"
821 << " gl_Position = vs_in_position_ndc;\n"
824 programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
826 // Create fragment shader
827 std::ostringstream fs;
829 fs << "#version 440\n"
831 << "layout(location = 0) out vec4 fs_out_color;\n"
833 << "void main (void)\n"
835 << " uint maskBitCount = 0u;\n"
837 << " for (int i = 0; i < 32; ++i)\n"
838 << " if (((gl_SampleMaskIn[0] >> i) & 0x01) == 0x01)\n"
839 << " ++maskBitCount;\n"
841 << " if (maskBitCount != 1u)\n"
842 << " fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
844 << " fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
847 programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
850 template<> TestInstance* MSCase<MSCaseSampleMaskBitCount>::createInstance (Context& context) const
852 return new MSInstance<MSInstanceSampleMaskBitCount>(context, m_imageMSParams);
855 class MSInstanceSampleMaskCorrectBit;
857 template<> MultisampleInstanceBase::VertexDataDesc MSInstance<MSInstanceSampleMaskCorrectBit>::getVertexDataDescripton (void) const
859 return getVertexDataDescriptonNdc();
862 template<> void MSInstance<MSInstanceSampleMaskCorrectBit>::uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const
864 uploadVertexDataNdc(vertexBufferAllocation, vertexDataDescripton);
867 template<> tcu::TestStatus MSInstance<MSInstanceSampleMaskCorrectBit>::verifyImageData (const vk::VkImageCreateInfo& imageMSInfo,
868 const vk::VkImageCreateInfo& imageRSInfo,
869 const std::vector<tcu::ConstPixelBufferAccess>& dataPerSample,
870 const tcu::ConstPixelBufferAccess& dataRS) const
872 DE_UNREF(imageRSInfo);
875 if (checkForErrorMS(imageMSInfo, dataPerSample, 0))
876 return tcu::TestStatus::fail("The bit corresponsing to current gl_SampleID is not set in gl_SampleMaskIn");
878 return tcu::TestStatus::pass("Passed");
881 class MSCaseSampleMaskCorrectBit;
883 template<> void MSCase<MSCaseSampleMaskCorrectBit>::init (void)
886 << tcu::TestLog::Message
887 << "Verifying gl_SampleMaskIn.\n"
888 << " Fragment shader will be invoked numSamples times.\n"
889 << " => In each invocation gl_SampleMaskIn should have the bit set that corresponds to gl_SampleID.\n"
890 << tcu::TestLog::EndMessage;
892 MultisampleCaseBase::init();
895 template<> void MSCase<MSCaseSampleMaskCorrectBit>::initPrograms (vk::SourceCollections& programCollection) const
897 MSCaseBaseResolveAndPerSampleFetch::initPrograms(programCollection);
899 // Create vertex shader
900 std::ostringstream vs;
902 vs << "#version 440\n"
903 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
905 << "out gl_PerVertex {\n"
906 << " vec4 gl_Position;\n"
908 << "void main (void)\n"
910 << " gl_Position = vs_in_position_ndc;\n"
913 programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
915 // Create fragment shader
916 std::ostringstream fs;
918 fs << "#version 440\n"
920 << "layout(location = 0) out vec4 fs_out_color;\n"
922 << "void main (void)\n"
924 << " if (((gl_SampleMaskIn[0] >> gl_SampleID) & 0x01) == 0x01)\n"
925 << " fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
927 << " fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
930 programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
933 template<> TestInstance* MSCase<MSCaseSampleMaskCorrectBit>::createInstance (Context& context) const
935 return new MSInstance<MSInstanceSampleMaskCorrectBit>(context, m_imageMSParams);
938 class MSInstanceSampleMaskWrite;
940 template<> MultisampleInstanceBase::VertexDataDesc MSInstance<MSInstanceSampleMaskWrite>::getVertexDataDescripton (void) const
942 return getVertexDataDescriptonNdc();
945 template<> void MSInstance<MSInstanceSampleMaskWrite>::uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const
947 uploadVertexDataNdc(vertexBufferAllocation, vertexDataDescripton);
950 template<> tcu::TestStatus MSInstance<MSInstanceSampleMaskWrite>::verifyImageData (const vk::VkImageCreateInfo& imageMSInfo,
951 const vk::VkImageCreateInfo& imageRSInfo,
952 const std::vector<tcu::ConstPixelBufferAccess>& dataPerSample,
953 const tcu::ConstPixelBufferAccess& dataRS) const
955 const deUint32 numSamples = static_cast<deUint32>(imageMSInfo.samples);
957 for (deUint32 z = 0u; z < imageMSInfo.extent.depth; ++z)
958 for (deUint32 y = 0u; y < imageMSInfo.extent.height; ++y)
959 for (deUint32 x = 0u; x < imageMSInfo.extent.width; ++x)
961 for (deUint32 sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
963 const deUint32 firstComponent = dataPerSample[sampleNdx].getPixelUint(x, y, z)[0];
965 if (firstComponent != 0u && firstComponent != 255u)
966 return tcu::TestStatus::fail("Expected color to be zero or saturated on the first channel");
970 for (deUint32 z = 0u; z < imageRSInfo.extent.depth; ++z)
971 for (deUint32 y = 0u; y < imageRSInfo.extent.height; ++y)
972 for (deUint32 x = 0u; x < imageRSInfo.extent.width; ++x)
974 const float firstComponent = dataRS.getPixel(x, y, z)[0];
976 if (deFloatAbs(firstComponent - 0.5f) > 0.02f)
977 return tcu::TestStatus::fail("Expected resolve color to be half intensity on the first channel");
980 return tcu::TestStatus::pass("Passed");
983 class MSCaseSampleMaskWrite;
985 template<> void MSCase<MSCaseSampleMaskWrite>::init (void)
988 << tcu::TestLog::Message
989 << "Discarding half of the samples using gl_SampleMask."
990 << "Expecting half intensity on multisample targets (numSamples > 1)\n"
991 << tcu::TestLog::EndMessage;
993 MultisampleCaseBase::init();
996 template<> void MSCase<MSCaseSampleMaskWrite>::initPrograms (vk::SourceCollections& programCollection) const
998 MSCaseBaseResolveAndPerSampleFetch::initPrograms(programCollection);
1000 // Create vertex shader
1001 std::ostringstream vs;
1003 vs << "#version 440\n"
1004 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
1006 << "out gl_PerVertex {\n"
1007 << " vec4 gl_Position;\n"
1009 << "void main (void)\n"
1011 << " gl_Position = vs_in_position_ndc;\n"
1014 programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
1016 // Create fragment shader
1017 std::ostringstream fs;
1019 fs << "#version 440\n"
1021 << "layout(location = 0) out vec4 fs_out_color;\n"
1023 << "void main (void)\n"
1025 << " gl_SampleMask[0] = 0xAAAAAAAA;\n"
1027 << " fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
1030 programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
1033 template<> TestInstance* MSCase<MSCaseSampleMaskWrite>::createInstance (Context& context) const
1035 return new MSInstance<MSInstanceSampleMaskWrite>(context, m_imageMSParams);
1040 tcu::TestCaseGroup* createMultisampleShaderBuiltInTests (tcu::TestContext& testCtx)
1042 de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "multisample_shader_builtin", "Multisample Shader BuiltIn Tests"));
1044 const tcu::UVec3 imageSizes[] =
1046 tcu::UVec3(128u, 128u, 1u),
1047 tcu::UVec3(137u, 191u, 1u),
1050 const deUint32 sizesElemCount = static_cast<deUint32>(sizeof(imageSizes) / sizeof(tcu::UVec3));
1052 const vk::VkSampleCountFlagBits samplesSetFull[] =
1054 vk::VK_SAMPLE_COUNT_2_BIT,
1055 vk::VK_SAMPLE_COUNT_4_BIT,
1056 vk::VK_SAMPLE_COUNT_8_BIT,
1057 vk::VK_SAMPLE_COUNT_16_BIT,
1058 vk::VK_SAMPLE_COUNT_32_BIT,
1059 vk::VK_SAMPLE_COUNT_64_BIT,
1062 const deUint32 samplesSetFullCount = static_cast<deUint32>(sizeof(samplesSetFull) / sizeof(vk::VkSampleCountFlagBits));
1064 testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseSampleID> >(testCtx, "sample_id", imageSizes, sizesElemCount, samplesSetFull, samplesSetFullCount));
1066 de::MovePtr<tcu::TestCaseGroup> samplePositionGroup(new tcu::TestCaseGroup(testCtx, "sample_position", "Sample Position Tests"));
1068 samplePositionGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseSamplePosDistribution> >(testCtx, "distribution", imageSizes, sizesElemCount, samplesSetFull, samplesSetFullCount));
1069 samplePositionGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseSamplePosCorrectness> > (testCtx, "correctness", imageSizes, sizesElemCount, samplesSetFull, samplesSetFullCount));
1071 testGroup->addChild(samplePositionGroup.release());
1073 const vk::VkSampleCountFlagBits samplesSetReduced[] =
1075 vk::VK_SAMPLE_COUNT_2_BIT,
1076 vk::VK_SAMPLE_COUNT_4_BIT,
1077 vk::VK_SAMPLE_COUNT_8_BIT,
1078 vk::VK_SAMPLE_COUNT_16_BIT,
1079 vk::VK_SAMPLE_COUNT_32_BIT,
1082 const deUint32 samplesSetReducedCount = static_cast<deUint32>(sizeof(samplesSetReduced) / sizeof(vk::VkSampleCountFlagBits));
1084 de::MovePtr<tcu::TestCaseGroup> sampleMaskGroup(new tcu::TestCaseGroup(testCtx, "sample_mask", "Sample Mask Tests"));
1086 sampleMaskGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseSampleMaskPattern> > (testCtx, "pattern", imageSizes, sizesElemCount, samplesSetReduced, samplesSetReducedCount));
1087 sampleMaskGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseSampleMaskBitCount> > (testCtx, "bit_count", imageSizes, sizesElemCount, samplesSetReduced, samplesSetReducedCount));
1088 sampleMaskGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseSampleMaskCorrectBit> >(testCtx, "correct_bit",imageSizes, sizesElemCount, samplesSetReduced, samplesSetReducedCount));
1089 sampleMaskGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseSampleMaskWrite> > (testCtx, "write", imageSizes, sizesElemCount, samplesSetReduced, samplesSetReducedCount));
1091 testGroup->addChild(sampleMaskGroup.release());
1093 return testGroup.release();