1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2019 Advanced Micro Devices, Inc.
6 * Copyright (c) 2019 The Khronos Group Inc.
7 * Copyright (c) 2023 LunarG, Inc.
8 * Copyright (c) 2023 Nintendo
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 *
22 *//*!
23 * \file
24 * \brief Tests for VK_AMD_shader_fragment_mask
25 *//*--------------------------------------------------------------------*/
26
27 #include "vktPipelineMultisampleShaderFragmentMaskTests.hpp"
28 #include "vktPipelineMakeUtil.hpp"
29 #include "vktTestCase.hpp"
30 #include "vktTestCaseUtil.hpp"
31 #include "vktTestGroupUtil.hpp"
32 #include "vktCustomInstancesDevices.hpp"
33 #include "tcuCommandLine.hpp"
34
35 #include "vkCmdUtil.hpp"
36 #include "vkObjUtil.hpp"
37 #include "vkPlatform.hpp"
38 #include "vkMemUtil.hpp"
39 #include "vkQueryUtil.hpp"
40 #include "vkTypeUtil.hpp"
41 #include "vkRefUtil.hpp"
42 #include "vkBuilderUtil.hpp"
43 #include "vkPrograms.hpp"
44 #include "vkImageUtil.hpp"
45
46 #include "deUniquePtr.hpp"
47 #include "deSharedPtr.hpp"
48 #include "deRandom.hpp"
49
50 #include "tcuVector.hpp"
51 #include "tcuTestLog.hpp"
52 #include "tcuImageCompare.hpp"
53 #include "tcuTestLog.hpp"
54 #include "tcuTextureUtil.hpp"
55
56 #include <string>
57 #include <vector>
58 #include <set>
59
60 namespace vkt
61 {
62 namespace pipeline
63 {
64 namespace
65 {
66 using namespace vk;
67 using de::MovePtr;
68 using de::SharedPtr;
69 using tcu::UVec2;
70 using tcu::UVec4;
71 using tcu::Vec2;
72 using tcu::Vec4;
73
74 typedef SharedPtr<Unique<VkImageView> > ImageViewSp;
75
76 struct PositionColor
77 {
78 tcu::Vec4 position;
79 VkClearColorValue color;
80
PositionColorvkt::pipeline::__anon9d4b69c50111::PositionColor81 PositionColor (const tcu::Vec4& pos, const tcu::UVec4& col) : position(pos)
82 {
83 deMemcpy(color.uint32, col.getPtr(), sizeof(color.uint32));
84 }
85
PositionColorvkt::pipeline::__anon9d4b69c50111::PositionColor86 PositionColor (const tcu::Vec4& pos, const tcu::Vec4& col) : position(pos)
87 {
88 deMemcpy(color.float32, col.getPtr(), sizeof(color.float32));
89 }
90
PositionColorvkt::pipeline::__anon9d4b69c50111::PositionColor91 PositionColor (const PositionColor& rhs)
92 : position (rhs.position)
93 , color (rhs.color)
94 {
95 }
96 };
97
98 //! Make a (unused) sampler.
makeSampler(const DeviceInterface & vk,const VkDevice device)99 Move<VkSampler> makeSampler (const DeviceInterface& vk, const VkDevice device)
100 {
101 const VkSamplerCreateInfo samplerParams =
102 {
103 VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, // VkStructureType sType;
104 DE_NULL, // const void* pNext;
105 (VkSamplerCreateFlags)0, // VkSamplerCreateFlags flags;
106 VK_FILTER_NEAREST, // VkFilter magFilter;
107 VK_FILTER_NEAREST, // VkFilter minFilter;
108 VK_SAMPLER_MIPMAP_MODE_NEAREST, // VkSamplerMipmapMode mipmapMode;
109 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeU;
110 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeV;
111 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeW;
112 0.0f, // float mipLodBias;
113 VK_FALSE, // VkBool32 anisotropyEnable;
114 1.0f, // float maxAnisotropy;
115 VK_FALSE, // VkBool32 compareEnable;
116 VK_COMPARE_OP_ALWAYS, // VkCompareOp compareOp;
117 0.0f, // float minLod;
118 0.0f, // float maxLod;
119 VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // VkBorderColor borderColor;
120 VK_FALSE, // VkBool32 unnormalizedCoordinates;
121 };
122 return createSampler(vk, device, &samplerParams);
123 }
124
makeImage(const DeviceInterface & vk,const VkDevice device,const VkFormat format,const UVec2 & size,const deUint32 layers,const VkSampleCountFlagBits samples,const VkImageUsageFlags usage)125 Move<VkImage> makeImage (const DeviceInterface& vk,
126 const VkDevice device,
127 const VkFormat format,
128 const UVec2& size,
129 const deUint32 layers,
130 const VkSampleCountFlagBits samples,
131 const VkImageUsageFlags usage)
132 {
133 const VkImageCreateInfo imageParams =
134 {
135 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
136 DE_NULL, // const void* pNext;
137 (VkImageCreateFlags)0, // VkImageCreateFlags flags;
138 VK_IMAGE_TYPE_2D, // VkImageType imageType;
139 format, // VkFormat format;
140 makeExtent3D(size.x(), size.y(), 1), // VkExtent3D extent;
141 1u, // deUint32 mipLevels;
142 layers, // deUint32 arrayLayers;
143 samples, // VkSampleCountFlagBits samples;
144 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
145 usage, // VkImageUsageFlags usage;
146 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
147 0u, // deUint32 queueFamilyIndexCount;
148 DE_NULL, // const deUint32* pQueueFamilyIndices;
149 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
150 };
151 return createImage(vk, device, &imageParams);
152 }
153
genShapes(const VkFormat colorFormat)154 std::vector<PositionColor> genShapes (const VkFormat colorFormat)
155 {
156 std::vector<PositionColor> vertices;
157
158 if (colorFormat == VK_FORMAT_R8G8B8A8_UNORM)
159 {
160 vertices.push_back(PositionColor(Vec4( 0.0f, -0.75f, 0.0f, 1.0f), Vec4(0.5f, 0.5f, 0.5f, 1.0f)));
161 vertices.push_back(PositionColor(Vec4(-0.75f, 0.75f, 0.0f, 1.0f), Vec4(1.0f, 0.5f, 0.5f, 1.0f)));
162 vertices.push_back(PositionColor(Vec4( 0.75f, 0.65f, 0.0f, 1.0f), Vec4(0.0f, 0.5f, 1.0f, 1.0f)));
163 }
164 else
165 {
166 vertices.push_back(PositionColor(Vec4( 0.0f, -0.75f, 0.0f, 1.0f), UVec4(0xabcdu, 0u, 0u, 0u)));
167 vertices.push_back(PositionColor(Vec4(-0.75f, 0.75f, 0.0f, 1.0f), UVec4(0xbcdeu, 0u, 0u, 0u)));
168 vertices.push_back(PositionColor(Vec4( 0.75f, 0.65f, 0.0f, 1.0f), UVec4(0xcdefu, 0u, 0u, 0u)));
169 }
170
171 return vertices;
172 }
173
174 //! Map color image format to a convenient format used in vertex attributes
getVertexInputColorFormat(const VkFormat colorImageFormat)175 VkFormat getVertexInputColorFormat (const VkFormat colorImageFormat)
176 {
177 switch (tcu::getTextureChannelClass(mapVkFormat(colorImageFormat).type))
178 {
179 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
180 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
181 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
182 return VK_FORMAT_R32G32B32A32_SFLOAT;
183
184 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
185 return VK_FORMAT_R32G32B32A32_SINT;
186
187 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
188 return VK_FORMAT_R32G32B32A32_UINT;
189
190 default:
191 DE_ASSERT(0);
192 return VK_FORMAT_UNDEFINED;
193 }
194 }
195
196 enum SampleSource
197 {
198 SAMPLE_SOURCE_IMAGE, //!< texel fetch from an image
199 SAMPLE_SOURCE_SUBPASS_INPUT, //!< texel fetch from an input attachment
200 };
201
202 // Class to wrap a singleton device for use in fragment mask tests,
203 // which require the VK_AMD_shader_fragment extension.
204 class SingletonDevice
205 {
SingletonDevice(Context & context)206 SingletonDevice(Context& context)
207 : m_context(context)
208 , m_logicalDevice()
209 {
210 const float queuePriority = 1.0;
211 const VkDeviceQueueCreateInfo queues[] =
212 {
213 {
214 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
215 DE_NULL,
216 (VkDeviceQueueCreateFlags)0,
217 m_context.getUniversalQueueFamilyIndex(),
218 1u, // queueCount
219 &queuePriority, // pQueuePriorities
220 }
221 };
222
223 const auto& vkp = m_context.getPlatformInterface();
224 const auto& vki = m_context.getInstanceInterface();
225 const auto instance = m_context.getInstance();
226 const auto physicalDevice = m_context.getPhysicalDevice();
227 std::vector<const char*> creationExtensions = m_context.getDeviceCreationExtensions();
228
229 VkPhysicalDeviceFeatures2 features2 = initVulkanStructure();
230 VkPhysicalDeviceDescriptorBufferFeaturesEXT descriptorBufferFeatures = initVulkanStructure();
231 VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT graphicsPipelineLibraryFeatures = initVulkanStructure();
232 VkPhysicalDeviceDynamicRenderingFeaturesKHR dynamicRenderingFeatures = initVulkanStructure();
233 VkPhysicalDeviceShaderObjectFeaturesEXT shaderObjectFeatures = initVulkanStructure(&dynamicRenderingFeatures);
234
235 m_context.requireInstanceFunctionality("VK_KHR_get_physical_device_properties2");
236 const auto addFeatures = makeStructChainAdder(&features2);
237
238 if (m_context.isDeviceFunctionalitySupported("VK_EXT_descriptor_buffer"))
239 addFeatures(&descriptorBufferFeatures);
240
241 if (m_context.isDeviceFunctionalitySupported("VK_EXT_graphics_pipeline_library"))
242 addFeatures(&graphicsPipelineLibraryFeatures);
243
244 if (m_context.isDeviceFunctionalitySupported("VK_EXT_shader_object"))
245 addFeatures(&shaderObjectFeatures);
246
247 vki.getPhysicalDeviceFeatures2(physicalDevice, &features2);
248 descriptorBufferFeatures.descriptorBuffer = VK_FALSE;
249 features2.features.robustBufferAccess = VK_FALSE; // Disable robustness features.
250 creationExtensions.push_back("VK_AMD_shader_fragment_mask");
251
252 VkDeviceCreateInfo createInfo = initVulkanStructure(&features2);
253 createInfo.flags = 0u;
254 createInfo.queueCreateInfoCount = de::arrayLength(queues);
255 createInfo.pQueueCreateInfos = queues;
256 createInfo.enabledLayerCount = 0u;
257 createInfo.ppEnabledLayerNames = nullptr;
258 createInfo.enabledExtensionCount = de::sizeU32(creationExtensions);
259 createInfo.ppEnabledExtensionNames = de::dataOrNull(creationExtensions);
260 createInfo.pEnabledFeatures = nullptr;
261
262 m_logicalDevice = createCustomDevice(
263 m_context.getTestContext().getCommandLine().isValidationEnabled(),
264 vkp,
265 instance,
266 vki,
267 physicalDevice,
268 &createInfo,
269 nullptr);
270
271 m_deviceDriver = de::MovePtr<DeviceDriver>(new DeviceDriver(vkp, instance, *m_logicalDevice, m_context.getUsedApiVersion()));
272 }
273
274 public:
~SingletonDevice()275 ~SingletonDevice()
276 {
277 }
278
getDevice(Context & context)279 static VkDevice getDevice(Context& context)
280 {
281 if (!m_singletonDevice)
282 m_singletonDevice = SharedPtr<SingletonDevice>(new SingletonDevice(context));
283 DE_ASSERT(m_singletonDevice);
284 return m_singletonDevice->m_logicalDevice.get();
285 }
286
getUniversalQueue(Context & context)287 static VkQueue getUniversalQueue(Context& context)
288 {
289 return getDeviceQueue(getDeviceInterface(context), getDevice(context), context.getUniversalQueueFamilyIndex(), 0);
290 }
291
getDeviceInterface(Context & context)292 static const DeviceInterface& getDeviceInterface(Context& context)
293 {
294 if (!m_singletonDevice)
295 m_singletonDevice = SharedPtr<SingletonDevice>(new SingletonDevice(context));
296 DE_ASSERT(m_singletonDevice);
297 return *(m_singletonDevice->m_deviceDriver.get());
298 }
299
destroy()300 static void destroy()
301 {
302 m_singletonDevice.clear();
303 }
304
305 private:
306 const Context& m_context;
307 Move<vk::VkDevice> m_logicalDevice;
308 de::MovePtr<vk::DeviceDriver> m_deviceDriver;
309 static SharedPtr<SingletonDevice> m_singletonDevice;
310 };
311
312 SharedPtr<SingletonDevice> SingletonDevice::m_singletonDevice;
313
314 //! The parameters that define a test case
315 struct TestParams
316 {
317 PipelineConstructionType pipelineConstructionType;
318 UVec2 renderSize;
319 deUint32 numLayers; //!< 1 or N for layered image
320 SampleSource sampleSource; //!< source of texel fetch
321 VkSampleCountFlagBits numColorSamples;
322 VkFormat colorFormat; //!< Color attachment format
323
TestParamsvkt::pipeline::__anon9d4b69c50111::TestParams324 TestParams (void)
325 : numLayers ()
326 , sampleSource (SAMPLE_SOURCE_IMAGE)
327 , numColorSamples ()
328 , colorFormat ()
329 {
330 }
331 };
332
checkRequirements(Context & context,TestParams params)333 void checkRequirements (Context& context, TestParams params)
334 {
335 const auto& vki = context.getInstanceInterface();
336 const auto physicalDevice = context.getPhysicalDevice();
337
338 const auto& supportedExtensions = enumerateCachedDeviceExtensionProperties(vki, physicalDevice);
339 if (!isExtensionStructSupported(supportedExtensions, RequiredExtension("VK_AMD_shader_fragment_mask")))
340 TCU_THROW(NotSupportedError, "VK_AMD_shader_fragment_mask not supported");
341
342 const auto& limits = context.getDeviceProperties().limits;
343
344 if ((limits.framebufferColorSampleCounts & params.numColorSamples) == 0u)
345 TCU_THROW(NotSupportedError, "framebufferColorSampleCounts: sample count not supported");
346
347 if ((isIntFormat(params.colorFormat) || isUintFormat(params.colorFormat)))
348 {
349 if ((limits.sampledImageIntegerSampleCounts & params.numColorSamples) == 0u)
350 TCU_THROW(NotSupportedError, "sampledImageIntegerSampleCounts: sample count not supported");
351 }
352 else
353 {
354 if ((limits.sampledImageColorSampleCounts & params.numColorSamples) == 0u)
355 TCU_THROW(NotSupportedError, "sampledImageColorSampleCounts: sample count not supported");
356 }
357
358 // In the subpass input case we have to store fetch results into a buffer for subsequent verification in a compute shader.
359 const bool requireFragmentStores = (params.sampleSource == SAMPLE_SOURCE_SUBPASS_INPUT);
360
361 if (requireFragmentStores)
362 {
363 if (!context.getDeviceFeatures().fragmentStoresAndAtomics)
364 TCU_THROW(NotSupportedError, "fragmentStoresAndAtomics: feature not supported");
365 }
366
367 checkPipelineConstructionRequirements(vki, physicalDevice, params.pipelineConstructionType);
368 }
369
370 //! Common data used by the test
371 struct WorkingData
372 {
373 deUint32 numVertices; //!< Number of vertices defined in the vertex buffer
374 Move<VkBuffer> vertexBuffer;
375 MovePtr<Allocation> vertexBufferAlloc;
376 Move<VkImage> colorImage; //!< Color image
377 MovePtr<Allocation> colorImageAlloc;
378 Move<VkImageView> colorImageView; //!< Color image view spanning all layers
379 Move<VkBuffer> colorBuffer; //!< Buffer used to copy image data
380 MovePtr<Allocation> colorBufferAlloc;
381 VkDeviceSize colorBufferSize;
382 Move<VkSampler> defaultSampler; //!< Unused sampler, we are using texel fetches
383
WorkingDatavkt::pipeline::__anon9d4b69c50111::WorkingData384 WorkingData (void)
385 : numVertices ()
386 , colorBufferSize ()
387 {
388 }
389 };
390
initPrograms(SourceCollections & programCollection,const TestParams params)391 void initPrograms (SourceCollections& programCollection, const TestParams params)
392 {
393 std::string colorType; //!< color pixel type used by image functions
394 std::string colorBufferType; //!< packed pixel type as stored in a ssbo
395 std::string colorBufferPack; //!< a cast or a function call when writing back color format to the ssbo
396 std::string colorFragInQualifier; //!< fragment shader color input qualifier
397 std::string samplerPrefix; //!< u, i, or empty
398
399 switch (params.colorFormat)
400 {
401 case VK_FORMAT_R8G8B8A8_UNORM:
402 colorType = "vec4";
403 colorBufferType = "uint";
404 colorBufferPack = "packUnorm4x8";
405 break;
406
407 case VK_FORMAT_R32_UINT:
408 colorType = "uint";
409 colorBufferType = "uint";
410 colorBufferPack = colorBufferType;
411 colorFragInQualifier = "flat";
412 samplerPrefix = "u";
413 break;
414
415 case VK_FORMAT_R32_SINT:
416 colorType = "int";
417 colorBufferType = "int";
418 colorBufferPack = colorBufferType;
419 colorFragInQualifier = "flat";
420 samplerPrefix = "i";
421 break;
422
423 default:
424 DE_FATAL("initPrograms not handled for this color format");
425 break;
426 }
427
428 // Vertex shader - position and color
429 {
430 std::ostringstream src;
431 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
432 << "\n"
433 << "layout(location = 0) in vec4 in_position;\n"
434 << "layout(location = 1) in " << colorType << " in_color;\n"
435 << "layout(location = 0) out " << colorType << " o_color;\n"
436 << "\n"
437 << "out gl_PerVertex {\n"
438 << " vec4 gl_Position;\n"
439 << "};\n"
440 << "\n"
441 << "void main(void)\n"
442 << "{\n"
443 // Introduce a variance in geometry per instance index which maps to the image layer
444 << " float a = 0.25 * float(gl_InstanceIndex);\n"
445 << " mat3 rm = mat3( cos(a), sin(a), 0.0,\n"
446 << " -sin(a), cos(a), 0.0,\n"
447 << " 0.0, 0.0, 1.0);\n"
448 << " vec2 rpos = (rm * vec3(in_position.xy, 1.0)).xy;\n"
449 << "\n"
450 << " gl_Position = vec4(rpos, in_position.zw);\n"
451 << " o_color = in_color;\n"
452 << "}\n";
453
454 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
455 }
456
457 // Vertex shader - no vertex data, fill viewport with one primitive
458 {
459 std::ostringstream src;
460 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
461 << "\n"
462 << "out gl_PerVertex {\n"
463 << " vec4 gl_Position;\n"
464 << "};\n"
465 << "\n"
466 << "void main(void)\n"
467 << "{\n"
468 // Specify an oversized triangle covering the whole viewport.
469 << " switch (gl_VertexIndex)\n"
470 << " {\n"
471 << " case 0:\n"
472 << " gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
473 << " break;\n"
474 << " case 1:\n"
475 << " gl_Position = vec4(-1.0, 3.0, 0.0, 1.0);\n"
476 << " break;\n"
477 << " case 2:\n"
478 << " gl_Position = vec4( 3.0, -1.0, 0.0, 1.0);\n"
479 << " break;\n"
480 << " }\n"
481 << "}\n";
482
483 programCollection.glslSources.add("vert_full") << glu::VertexSource(src.str());
484 }
485
486 // Fragment shader - output color from VS
487 {
488 std::ostringstream src;
489 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
490 << "\n"
491 << "layout(location = 0) in " << colorFragInQualifier << " " << colorType << " in_color;\n"
492 << "layout(location = 0) out " << colorType << " o_color;\n"
493 << "\n"
494 << "void main(void)\n"
495 << "{\n"
496 << " o_color = in_color;\n"
497 << "}\n";
498
499 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
500 }
501
502 // Fragment shader - FMASK fetch from an input attachment
503 if (params.sampleSource == SAMPLE_SOURCE_SUBPASS_INPUT)
504 {
505 std::ostringstream src;
506 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
507 << "#extension GL_AMD_shader_fragment_mask : enable\n"
508 << "\n"
509 << "layout(set = 0, binding = 0) uniform " << samplerPrefix << "sampler2DMS" << (params.numLayers > 1 ? "Array" : "") << " u_image;\n"
510 << "layout(set = 0, binding = 1, std430) writeonly buffer ColorOutput {\n"
511 << " " << colorBufferType << " color[];\n"
512 << "} sb_out;\n"
513 << "layout(input_attachment_index = 0, set = 0, binding = 2) uniform " << samplerPrefix << "subpassInputMS" << " input_attach;\n"
514 << "\n"
515 << "void main(void)\n"
516 << "{\n"
517 << " ivec2 p = ivec2(gl_FragCoord.xy);\n"
518 << " int width = " << params.renderSize.x() << ";\n"
519 << " int numSamples = " << static_cast<deUint32>(params.numColorSamples) << ";\n"
520 << " int colorOutNdx = numSamples * (p.x + width * p.y);\n"
521 << "\n"
522 << " uint mask = fragmentMaskFetchAMD(input_attach);\n"
523 << " for (int sampleNdx = 0; sampleNdx < numSamples; ++sampleNdx)\n"
524 << " {\n"
525 << " int fragNdx = int((mask >> (4 * sampleNdx)) & 0xf);\n"
526 << " " << samplerPrefix << "vec4 color = fragmentFetchAMD(input_attach, fragNdx);\n"
527 << " sb_out.color[colorOutNdx + sampleNdx] = " << colorBufferPack << "(color);\n"
528 << " }\n"
529 << "}\n";
530
531 programCollection.glslSources.add("frag_fmask_fetch") << glu::FragmentSource(src.str());
532 }
533
534 // Generate compute shaders
535 const struct ComputeShaderParams
536 {
537 const char* name;
538 bool isFmaskFetch;
539 bool enabled;
540 } computeShaders[] =
541 {
542 // name // FMASK? // enabled?
543 { "comp_fetch", false, true, },
544 { "comp_fmask_fetch", true, (params.sampleSource != SAMPLE_SOURCE_SUBPASS_INPUT) },
545 };
546
547 for (const ComputeShaderParams* pShaderParams = computeShaders; pShaderParams != DE_ARRAY_END(computeShaders); ++pShaderParams)
548 if (pShaderParams->enabled)
549 {
550 const std::string samplingPos = (params.numLayers == 1 ? "ivec2(gl_WorkGroupID.xy)"
551 : "ivec3(gl_WorkGroupID)");
552 std::ostringstream src;
553 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
554 << (pShaderParams->isFmaskFetch ? "#extension GL_AMD_shader_fragment_mask : enable\n" : "")
555 << "#define NUM_SAMPLES " << static_cast<deUint32>(params.numColorSamples) << "\n"
556 << "\n"
557 << "layout(local_size_x = NUM_SAMPLES) in;\n" // one work group per pixel, each sample gets a local invocation
558 << "\n"
559 << "layout(set = 0, binding = 0) uniform " << samplerPrefix << "sampler2DMS" << (params.numLayers > 1 ? "Array" : "") << " u_image;\n"
560 << "layout(set = 0, binding = 1, std430) writeonly buffer ColorOutput {\n"
561 << " " << colorBufferType << " color[];\n"
562 << "} sb_out;\n"
563 << "\n"
564 << "void main(void)\n"
565 << "{\n"
566 << " int sampleNdx = int(gl_LocalInvocationID.x);\n"
567 << " int colorOutNdx = NUM_SAMPLES * int(gl_WorkGroupID.x +\n"
568 << " gl_WorkGroupID.y * gl_NumWorkGroups.x +\n"
569 << " gl_WorkGroupID.z * gl_NumWorkGroups.x * gl_NumWorkGroups.y);\n"
570 << "\n";
571 if (pShaderParams->isFmaskFetch)
572 {
573 src << " uint mask = fragmentMaskFetchAMD(u_image, " << samplingPos << ");\n"
574 << " int fragNdx = int((mask >> (4 * sampleNdx)) & 0xf);\n"
575 << " " << samplerPrefix << "vec4 color = fragmentFetchAMD(u_image, " << samplingPos << ", fragNdx);\n"
576 << " sb_out.color[colorOutNdx + sampleNdx] = " << colorBufferPack << "(color);\n";
577 }
578 else
579 {
580 src << " " << samplerPrefix << "vec4 color = texelFetch(u_image, " << samplingPos << ", sampleNdx);\n"
581 << " sb_out.color[colorOutNdx + sampleNdx] = " << colorBufferPack << "(color);\n";
582 }
583 src << "}\n";
584
585 programCollection.glslSources.add(pShaderParams->name) << glu::ComputeSource(src.str());
586 }
587 }
588
genClearValues(const VkFormat format,const deUint32 count)589 std::vector<VkClearValue> genClearValues (const VkFormat format, const deUint32 count)
590 {
591 std::vector<VkClearValue> clearValues;
592 de::Random rng (332);
593
594 switch (format)
595 {
596 case VK_FORMAT_R8G8B8A8_UNORM:
597 for (deUint32 i = 0u; i < count; ++i)
598 clearValues.push_back(makeClearValueColorF32(rng.getFloat(), rng.getFloat(), rng.getFloat(), 1.0f));
599 break;
600
601 case VK_FORMAT_R32_UINT:
602 case VK_FORMAT_R32_SINT:
603 for (deUint32 i = 0u; i < count; ++i)
604 clearValues.push_back(makeClearValueColorU32(rng.getUint32(), 0u, 0u, 0u));
605 break;
606
607 default:
608 DE_FATAL("Clear color not defined for this format");
609 break;
610 }
611
612 return clearValues;
613 }
614
615 //! For subpass load case draw and fetch must happen within the same render pass.
drawAndSampleInputAttachment(Context & context,const TestParams & params,WorkingData & wd)616 void drawAndSampleInputAttachment (Context& context, const TestParams& params, WorkingData& wd)
617 {
618 DE_ASSERT(params.numLayers == 1u); // subpass load with single-layer image
619
620 const InstanceInterface& vki = context.getInstanceInterface();
621 const DeviceInterface& vk = SingletonDevice::getDeviceInterface(context);
622 const VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
623 const VkDevice device = SingletonDevice::getDevice(context);
624
625 RenderPassWrapper renderPass;
626
627 // Create descriptor set
628 const Unique<VkDescriptorSetLayout> descriptorSetLayout (DescriptorSetLayoutBuilder()
629 .addSingleSamplerBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, &wd.defaultSampler.get())
630 .addSingleBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT)
631 .addSingleBinding (VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, VK_SHADER_STAGE_FRAGMENT_BIT)
632 .build(vk, device));
633
634 const Unique<VkDescriptorPool> descriptorPool (DescriptorPoolBuilder()
635 .addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
636 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
637 .addType(VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)
638 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
639
640 const Unique<VkDescriptorSet> descriptorSet (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
641
642 {
643 const VkDescriptorImageInfo colorImageInfo = makeDescriptorImageInfo(DE_NULL, *wd.colorImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
644 const VkDescriptorBufferInfo bufferInfo = makeDescriptorBufferInfo(*wd.colorBuffer, 0u, wd.colorBufferSize);
645
646 DescriptorSetUpdateBuilder builder;
647
648 builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &colorImageInfo);
649 builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &bufferInfo);
650
651 if (params.sampleSource == SAMPLE_SOURCE_SUBPASS_INPUT)
652 builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(2u), VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, &colorImageInfo);
653
654 builder.update(vk, device);
655 }
656
657 // Create a render pass and a framebuffer
658 {
659 std::vector<VkSubpassDescription> subpasses;
660 std::vector<VkSubpassDependency> subpassDependencies;
661 std::vector<VkImage> images;
662 std::vector<VkImageView> attachments;
663 std::vector<VkAttachmentDescription> attachmentDescriptions;
664 std::vector<VkAttachmentReference> attachmentReferences;
665
666 // Reserve capacity to avoid invalidating pointers to elements
667 attachmentReferences.reserve(2); // color image + input attachment
668
669 // Create a MS draw subpass
670 {
671 images.push_back(*wd.colorImage);
672 attachments.push_back(*wd.colorImageView);
673
674 attachmentDescriptions.push_back(makeAttachmentDescription(
675 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags;
676 params.colorFormat, // VkFormat format;
677 params.numColorSamples, // VkSampleCountFlagBits samples;
678 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
679 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
680 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
681 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
682 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
683 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL // VkImageLayout finalLayout;
684 ));
685
686 attachmentReferences.push_back(makeAttachmentReference(static_cast<deUint32>(attachmentReferences.size()), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
687 const VkAttachmentReference* colorRef = &attachmentReferences.back();
688
689 const VkSubpassDescription subpassDescription =
690 {
691 (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags;
692 VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
693 0u, // uint32_t inputAttachmentCount;
694 DE_NULL, // const VkAttachmentReference* pInputAttachments;
695 1u, // uint32_t colorAttachmentCount;
696 colorRef, // const VkAttachmentReference* pColorAttachments;
697 DE_NULL, // const VkAttachmentReference* pResolveAttachments;
698 DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment;
699 0u, // uint32_t preserveAttachmentCount;
700 DE_NULL, // const uint32_t* pPreserveAttachments;
701 };
702
703 subpasses.push_back(subpassDescription);
704 }
705
706 // Create a sampling subpass
707 {
708 attachmentReferences.push_back(makeAttachmentReference(0u, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL));
709 const VkAttachmentReference* inputRef = &attachmentReferences.back();
710
711 // No color attachment, side effects only
712 VkSubpassDescription subpassDescription =
713 {
714 (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags;
715 VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
716 1u, // uint32_t inputAttachmentCount;
717 inputRef, // const VkAttachmentReference* pInputAttachments;
718 0u, // uint32_t colorAttachmentCount;
719 DE_NULL, // const VkAttachmentReference* pColorAttachments;
720 DE_NULL, // const VkAttachmentReference* pResolveAttachments;
721 DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment;
722 0u, // uint32_t preserveAttachmentCount;
723 DE_NULL, // const uint32_t* pPreserveAttachments;
724 };
725
726 subpasses.push_back(subpassDescription);
727 }
728
729 // Serialize the subpasses
730 {
731 const VkAccessFlags dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
732 | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT
733 | VK_ACCESS_SHADER_WRITE_BIT;
734 const VkSubpassDependency dependency =
735 {
736 0u, // uint32_t srcSubpass;
737 1u, // uint32_t dstSubpass;
738 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags srcStageMask;
739 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags dstStageMask;
740 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask;
741 dstAccessMask, // VkAccessFlags dstAccessMask;
742 VK_DEPENDENCY_BY_REGION_BIT, // VkDependencyFlags dependencyFlags;
743 };
744 subpassDependencies.push_back(dependency);
745 }
746
747 VkRenderPassCreateInfo renderPassInfo =
748 {
749 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
750 DE_NULL, // const void* pNext;
751 (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags;
752 static_cast<deUint32>(attachmentDescriptions.size()), // deUint32 attachmentCount;
753 dataOrNullPtr(attachmentDescriptions), // const VkAttachmentDescription* pAttachments;
754 static_cast<deUint32>(subpasses.size()), // deUint32 subpassCount;
755 dataOrNullPtr(subpasses), // const VkSubpassDescription* pSubpasses;
756 static_cast<deUint32>(subpassDependencies.size()), // deUint32 dependencyCount;
757 dataOrNullPtr(subpassDependencies), // const VkSubpassDependency* pDependencies;
758 };
759
760 renderPass = RenderPassWrapper(params.pipelineConstructionType, vk, device, &renderPassInfo);
761 renderPass.createFramebuffer(vk, device, static_cast<deUint32>(attachments.size()), dataOrNullPtr(images), dataOrNullPtr(attachments), params.renderSize.x(), params.renderSize.y());
762 }
763
764 const std::vector<VkViewport> viewports { makeViewport(params.renderSize) };
765 const std::vector<VkRect2D> scissors { makeRect2D(params.renderSize) };
766
767 VkPipelineMultisampleStateCreateInfo multisampleStateInfo
768 {
769 VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
770 DE_NULL, // const void* pNext;
771 (VkPipelineMultisampleStateCreateFlags)0, // VkPipelineMultisampleStateCreateFlags flags;
772 params.numColorSamples, // VkSampleCountFlagBits rasterizationSamples;
773 VK_FALSE, // VkBool32 sampleShadingEnable;
774 1.0f, // float minSampleShading;
775 DE_NULL, // const VkSampleMask* pSampleMask;
776 VK_FALSE, // VkBool32 alphaToCoverageEnable;
777 VK_FALSE // VkBool32 alphaToOneEnable;
778 };
779
780 const VkPipelineColorBlendAttachmentState defaultBlendAttachmentState
781 {
782 VK_FALSE, // VkBool32 blendEnable;
783 VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor;
784 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor;
785 VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp;
786 VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor;
787 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor;
788 VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp;
789 0xf, // VkColorComponentFlags colorWriteMask;
790 };
791
792 VkPipelineColorBlendStateCreateInfo colorBlendStateInfo
793 {
794 VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
795 DE_NULL, // const void* pNext;
796 (VkPipelineColorBlendStateCreateFlags)0, // VkPipelineColorBlendStateCreateFlags flags;
797 VK_FALSE, // VkBool32 logicOpEnable;
798 VK_LOGIC_OP_COPY, // VkLogicOp logicOp;
799 1u, // deUint32 attachmentCount;
800 &defaultBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
801 { 0.0f, 0.0f, 0.0f, 0.0f }, // float blendConstants[4];
802 };
803
804 const ShaderWrapper vertexModuleDraw (ShaderWrapper(vk, device, context.getBinaryCollection().get("vert"), 0u));
805 const ShaderWrapper fragmentModuleDraw (ShaderWrapper(vk, device, context.getBinaryCollection().get("frag"), 0u));
806
807 // Create pipelines for MS draw
808 const PipelineLayoutWrapper pipelineLayout (params.pipelineConstructionType, vk, device, *descriptorSetLayout);
809 GraphicsPipelineWrapper pipelineDraw (vki, vk, physicalDevice, device, context.getDeviceExtensions(), params.pipelineConstructionType);
810 {
811 // Vertex attributes: position and color
812 VkVertexInputBindingDescription vertexInputBindingDescriptions = makeVertexInputBindingDescription(0u, sizeof(PositionColor), VK_VERTEX_INPUT_RATE_VERTEX);
813 std::vector<VkVertexInputAttributeDescription> vertexInputAttributeDescriptions
814 {
815 makeVertexInputAttributeDescription(0u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, 0u),
816 makeVertexInputAttributeDescription(1u, 0u, getVertexInputColorFormat(params.colorFormat), sizeof(Vec4))
817 };
818
819 const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo
820 {
821 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
822 DE_NULL, // const void* pNext;
823 (VkPipelineVertexInputStateCreateFlags)0, // VkPipelineVertexInputStateCreateFlags flags;
824 1u, // uint32_t vertexBindingDescriptionCount;
825 &vertexInputBindingDescriptions, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
826 static_cast<deUint32>(vertexInputAttributeDescriptions.size()), // uint32_t vertexAttributeDescriptionCount;
827 vertexInputAttributeDescriptions.data(), // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
828 };
829
830 pipelineDraw.setDefaultRasterizationState()
831 .setDefaultDepthStencilState()
832 .setupVertexInputState(&vertexInputStateInfo)
833 .setupPreRasterizationShaderState(viewports,
834 scissors,
835 pipelineLayout,
836 *renderPass,
837 0u,
838 vertexModuleDraw)
839 .setupFragmentShaderState(pipelineLayout, *renderPass, 0u, fragmentModuleDraw, DE_NULL, &multisampleStateInfo)
840 .setupFragmentOutputState(*renderPass, 0u, &colorBlendStateInfo, &multisampleStateInfo)
841 .setMonolithicPipelineLayout(pipelineLayout)
842 .buildPipeline();
843 }
844
845 // Sampling pass is single-sampled, output to storage buffer
846 const ShaderWrapper vertexModuleSample (ShaderWrapper(vk, device, context.getBinaryCollection().get("vert_full"), 0u));
847 const ShaderWrapper fragmentModuleSample (ShaderWrapper(vk, device, context.getBinaryCollection().get("frag_fmask_fetch"), 0u));
848
849 // Sampling pipeline
850 GraphicsPipelineWrapper pipelineSample(vki, vk, physicalDevice, device, context.getDeviceExtensions(), params.pipelineConstructionType);
851 {
852 VkPipelineVertexInputStateCreateInfo vertexInputStateInfo;
853 deMemset(&vertexInputStateInfo, 0, sizeof(vertexInputStateInfo));
854 vertexInputStateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
855
856 multisampleStateInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
857 colorBlendStateInfo.attachmentCount = 0u;
858
859 pipelineSample.setDefaultRasterizationState()
860 .setDefaultDepthStencilState()
861 .setupVertexInputState(&vertexInputStateInfo)
862 .setupPreRasterizationShaderState(viewports,
863 scissors,
864 pipelineLayout,
865 *renderPass,
866 1u,
867 vertexModuleSample)
868 .setupFragmentShaderState(pipelineLayout, *renderPass, 1u, fragmentModuleSample, DE_NULL, &multisampleStateInfo)
869 .setupFragmentOutputState(*renderPass, 1u, &colorBlendStateInfo, &multisampleStateInfo)
870 .setMonolithicPipelineLayout(pipelineLayout)
871 .buildPipeline();
872 }
873
874 const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, context.getUniversalQueueFamilyIndex()));
875 const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer(vk, device, *cmdPool));
876
877 beginCommandBuffer(vk, *cmdBuffer);
878
879 {
880 // Generate clear values
881 std::vector<VkClearValue> clearValues = genClearValues(params.colorFormat, params.numLayers);
882
883 const VkRect2D renderArea =
884 {
885 { 0u, 0u },
886 { params.renderSize.x(), params.renderSize.y() }
887 };
888 renderPass.begin(vk, *cmdBuffer, renderArea, static_cast<deUint32>(clearValues.size()), dataOrNullPtr(clearValues));
889 }
890
891 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
892
893 {
894 const VkDeviceSize vertexBufferOffset = 0ull;
895 vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &wd.vertexBuffer.get(), &vertexBufferOffset);
896 }
897
898 pipelineDraw.bind(*cmdBuffer);
899 vk.cmdDraw(*cmdBuffer, wd.numVertices, 1u, 0u, 0u);
900
901 renderPass.nextSubpass(vk, *cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
902
903 pipelineSample.bind(*cmdBuffer);
904 vk.cmdDraw(*cmdBuffer, 3u, 1u, 0u, 0u); // fill the framebuffer, geometry defined in the VS
905
906 renderPass.end(vk, *cmdBuffer);
907
908 // Buffer write barrier
909 {
910 const VkBufferMemoryBarrier barrier =
911 {
912 VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType;
913 DE_NULL, // const void* pNext;
914 VK_ACCESS_SHADER_WRITE_BIT, // VkAccessFlags srcAccessMask;
915 VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask;
916 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
917 VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex;
918 *wd.colorBuffer, // VkBuffer buffer;
919 0ull, // VkDeviceSize offset;
920 VK_WHOLE_SIZE, // VkDeviceSize size;
921 };
922
923 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 0u, DE_NULL, 1u, &barrier, DE_NULL, 0u);
924 }
925
926 VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
927 submitCommandsAndWait(vk, device, SingletonDevice::getUniversalQueue(context), *cmdBuffer);
928
929 invalidateMappedMemoryRange(vk, device, wd.colorBufferAlloc->getMemory(), wd.colorBufferAlloc->getOffset(), VK_WHOLE_SIZE);
930 }
931
932 //! Only draw a multisampled image
draw(Context & context,const TestParams & params,WorkingData & wd)933 void draw (Context& context, const TestParams& params, WorkingData& wd)
934 {
935 const InstanceInterface & vki = context.getInstanceInterface();
936 const DeviceInterface& vk = SingletonDevice::getDeviceInterface(context);
937 const VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
938 const VkDevice device = SingletonDevice::getDevice(context);
939
940 std::vector<ImageViewSp> imageViews;
941 RenderPassWrapper renderPass;
942
943 // Create color attachments
944 for (deUint32 layerNdx = 0u; layerNdx < params.numLayers; ++layerNdx)
945 {
946 imageViews.push_back(ImageViewSp(new Unique<VkImageView>(
947 makeImageView(vk, device, *wd.colorImage, VK_IMAGE_VIEW_TYPE_2D, params.colorFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, layerNdx, 1u)))));
948 }
949
950 // Create a render pass and a framebuffer
951 {
952 std::vector<VkSubpassDescription> subpasses;
953 std::vector<VkImage> images;
954 std::vector<VkImageView> attachments;
955 std::vector<VkAttachmentDescription> attachmentDescriptions;
956 std::vector<VkAttachmentReference> attachmentReferences;
957
958 // Reserve capacity to avoid invalidating pointers to elements
959 attachmentReferences.reserve(params.numLayers);
960
961 // Create MS draw subpasses
962 for (deUint32 layerNdx = 0u; layerNdx < params.numLayers; ++layerNdx)
963 {
964 images.push_back(*wd.colorImage);
965 attachments.push_back(**imageViews[layerNdx]);
966
967 attachmentDescriptions.push_back(makeAttachmentDescription(
968 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags;
969 params.colorFormat, // VkFormat format;
970 params.numColorSamples, // VkSampleCountFlagBits samples;
971 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
972 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
973 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
974 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
975 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
976 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL // VkImageLayout finalLayout;
977 ));
978
979 attachmentReferences.push_back(makeAttachmentReference(static_cast<deUint32>(attachmentReferences.size()), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
980 const VkAttachmentReference* colorRef = &attachmentReferences.back();
981
982 const VkSubpassDescription subpassDescription =
983 {
984 (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags;
985 VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
986 0u, // uint32_t inputAttachmentCount;
987 DE_NULL, // const VkAttachmentReference* pInputAttachments;
988 1u, // uint32_t colorAttachmentCount;
989 colorRef, // const VkAttachmentReference* pColorAttachments;
990 DE_NULL, // const VkAttachmentReference* pResolveAttachments;
991 DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment;
992 0u, // uint32_t preserveAttachmentCount;
993 DE_NULL, // const uint32_t* pPreserveAttachments;
994 };
995
996 subpasses.push_back(subpassDescription);
997 }
998
999 // All MS image drawing subpasses are independent
1000 VkRenderPassCreateInfo renderPassInfo =
1001 {
1002 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
1003 DE_NULL, // const void* pNext;
1004 (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags;
1005 static_cast<deUint32>(attachmentDescriptions.size()), // deUint32 attachmentCount;
1006 dataOrNullPtr(attachmentDescriptions), // const VkAttachmentDescription* pAttachments;
1007 static_cast<deUint32>(subpasses.size()), // deUint32 subpassCount;
1008 dataOrNullPtr(subpasses), // const VkSubpassDescription* pSubpasses;
1009 0u, // deUint32 dependencyCount;
1010 DE_NULL, // const VkSubpassDependency* pDependencies;
1011 };
1012
1013 renderPass = RenderPassWrapper(params.pipelineConstructionType, vk, device, &renderPassInfo);
1014 renderPass.createFramebuffer(vk, device, static_cast<deUint32>(attachments.size()), dataOrNullPtr(images), dataOrNullPtr(attachments), params.renderSize.x(), params.renderSize.y());
1015 }
1016
1017 const PipelineLayoutWrapper pipelineLayout (params.pipelineConstructionType, vk, device);
1018 const ShaderWrapper vertexModuleDraw (ShaderWrapper(vk, device, context.getBinaryCollection().get("vert"), 0u));
1019 const ShaderWrapper fragmentModuleDraw (ShaderWrapper(vk, device, context.getBinaryCollection().get("frag"), 0u));
1020
1021 // Vertex attributes: position and color
1022 VkVertexInputBindingDescription vertexInputBindingDescriptions = makeVertexInputBindingDescription(0u, sizeof(PositionColor), VK_VERTEX_INPUT_RATE_VERTEX);
1023 std::vector<VkVertexInputAttributeDescription> vertexInputAttributeDescriptions
1024 {
1025 makeVertexInputAttributeDescription(0u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, 0u),
1026 makeVertexInputAttributeDescription(1u, 0u, getVertexInputColorFormat(params.colorFormat), sizeof(Vec4))
1027 };
1028
1029 const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo
1030 {
1031 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
1032 DE_NULL, // const void* pNext;
1033 (VkPipelineVertexInputStateCreateFlags)0, // VkPipelineVertexInputStateCreateFlags flags;
1034 1u, // uint32_t vertexBindingDescriptionCount;
1035 &vertexInputBindingDescriptions, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
1036 static_cast<deUint32>(vertexInputAttributeDescriptions.size()), // uint32_t vertexAttributeDescriptionCount;
1037 vertexInputAttributeDescriptions.data(), // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
1038 };
1039
1040 const std::vector<VkViewport> viewports { makeViewport(params.renderSize) };
1041 const std::vector<VkRect2D> scissors { makeRect2D(params.renderSize) };
1042
1043 const VkPipelineMultisampleStateCreateInfo multisampleStateInfo
1044 {
1045 VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
1046 DE_NULL, // const void* pNext;
1047 (VkPipelineMultisampleStateCreateFlags)0, // VkPipelineMultisampleStateCreateFlags flags;
1048 params.numColorSamples, // VkSampleCountFlagBits rasterizationSamples;
1049 VK_FALSE, // VkBool32 sampleShadingEnable;
1050 1.0f, // float minSampleShading;
1051 DE_NULL, // const VkSampleMask* pSampleMask;
1052 VK_FALSE, // VkBool32 alphaToCoverageEnable;
1053 VK_FALSE // VkBool32 alphaToOneEnable;
1054 };
1055
1056 const VkPipelineColorBlendAttachmentState defaultBlendAttachmentState
1057 {
1058 VK_FALSE, // VkBool32 blendEnable;
1059 VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor;
1060 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor;
1061 VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp;
1062 VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor;
1063 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor;
1064 VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp;
1065 0xf, // VkColorComponentFlags colorWriteMask;
1066 };
1067
1068 VkPipelineColorBlendStateCreateInfo colorBlendStateInfo
1069 {
1070 VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
1071 DE_NULL, // const void* pNext;
1072 (VkPipelineColorBlendStateCreateFlags)0, // VkPipelineColorBlendStateCreateFlags flags;
1073 VK_FALSE, // VkBool32 logicOpEnable;
1074 VK_LOGIC_OP_COPY, // VkLogicOp logicOp;
1075 1u, // deUint32 attachmentCount;
1076 &defaultBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
1077 { 0.0f, 0.0f, 0.0f, 0.0f }, // float blendConstants[4];
1078 };
1079
1080 // Create pipelines for MS draw
1081 std::vector<GraphicsPipelineWrapper> pipelines;
1082 pipelines.reserve(params.numLayers);
1083 for (deUint32 layerNdx = 0u; layerNdx < params.numLayers; ++layerNdx)
1084 {
1085 pipelines.emplace_back(vki, vk, physicalDevice, device, context.getDeviceExtensions(), params.pipelineConstructionType);
1086 pipelines.back().setDefaultRasterizationState()
1087 .setDefaultColorBlendState()
1088 .setDefaultDepthStencilState()
1089 .setupVertexInputState(&vertexInputStateInfo)
1090 .setupPreRasterizationShaderState(viewports,
1091 scissors,
1092 pipelineLayout,
1093 *renderPass,
1094 layerNdx,
1095 vertexModuleDraw)
1096 .setupFragmentShaderState(pipelineLayout, *renderPass, layerNdx, fragmentModuleDraw, DE_NULL, &multisampleStateInfo)
1097 .setupFragmentOutputState(*renderPass, layerNdx, &colorBlendStateInfo, &multisampleStateInfo)
1098 .setMonolithicPipelineLayout(pipelineLayout)
1099 .buildPipeline();
1100 }
1101
1102 const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, context.getUniversalQueueFamilyIndex()));
1103 const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer(vk, device, *cmdPool));
1104
1105 beginCommandBuffer(vk, *cmdBuffer);
1106
1107 {
1108 // Generate clear values
1109 std::vector<VkClearValue> clearValues = genClearValues(params.colorFormat, params.numLayers);
1110
1111 const VkRect2D renderArea =
1112 {
1113 { 0u, 0u },
1114 { params.renderSize.x(), params.renderSize.y() }
1115 };
1116
1117 renderPass.begin(vk, *cmdBuffer, renderArea, static_cast<deUint32>(clearValues.size()), dataOrNullPtr(clearValues));
1118 }
1119
1120 {
1121 const VkDeviceSize vertexBufferOffset = 0ull;
1122 vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &wd.vertexBuffer.get(), &vertexBufferOffset);
1123 }
1124
1125 for (deUint32 layerNdx = 0u; layerNdx < params.numLayers; ++layerNdx)
1126 {
1127 if (layerNdx != 0u)
1128 renderPass.nextSubpass(vk, *cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
1129
1130 pipelines[layerNdx].bind(*cmdBuffer);
1131 vk.cmdDraw(*cmdBuffer, wd.numVertices, 1u, 0u, layerNdx); // pass instance index to slightly change geometry per layer
1132 }
1133
1134 renderPass.end(vk, *cmdBuffer);
1135
1136 VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
1137 submitCommandsAndWait(vk, device, SingletonDevice::getUniversalQueue(context), *cmdBuffer);
1138 }
1139
1140 //! Sample from an image in a compute shader, storing the result in a color buffer
dispatchSampleImage(Context & context,const TestParams & params,WorkingData & wd,const std::string & shaderName)1141 void dispatchSampleImage (Context& context, const TestParams& params, WorkingData& wd, const std::string& shaderName)
1142 {
1143 const DeviceInterface& vk = SingletonDevice::getDeviceInterface(context);
1144 const VkDevice device = SingletonDevice::getDevice(context);
1145
1146 // Create descriptor set
1147
1148 const Unique<VkDescriptorSetLayout> descriptorSetLayout(
1149 DescriptorSetLayoutBuilder()
1150 .addSingleSamplerBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_COMPUTE_BIT, &wd.defaultSampler.get())
1151 .addSingleBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
1152 .build(vk, device));
1153
1154 const Unique<VkDescriptorPool> descriptorPool(
1155 DescriptorPoolBuilder()
1156 .addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
1157 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
1158 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
1159
1160 const Unique<VkDescriptorSet> descriptorSet(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
1161
1162 {
1163 const VkDescriptorImageInfo colorImageInfo = makeDescriptorImageInfo(DE_NULL, *wd.colorImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
1164 const VkDescriptorBufferInfo resultBufferInfo = makeDescriptorBufferInfo(*wd.colorBuffer, 0ull, wd.colorBufferSize);
1165
1166 DescriptorSetUpdateBuilder builder;
1167
1168 builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &colorImageInfo);
1169 builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultBufferInfo);
1170
1171 builder.update(vk, device);
1172 }
1173
1174 // Pipeline
1175
1176 const Unique<VkShaderModule> shaderModule (createShaderModule(vk, device, context.getBinaryCollection().get(shaderName), 0u));
1177 const Unique<VkPipelineLayout> pipelineLayout (makePipelineLayout(vk, device, *descriptorSetLayout));
1178 const Unique<VkPipeline> pipeline (makeComputePipeline(vk, device, *pipelineLayout, *shaderModule));
1179
1180 const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, context.getUniversalQueueFamilyIndex()));
1181 const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer(vk, device, *cmdPool));
1182
1183 beginCommandBuffer(vk, *cmdBuffer);
1184
1185 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
1186 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
1187
1188 vk.cmdDispatch(*cmdBuffer, params.renderSize.x(), params.renderSize.y(), params.numLayers);
1189
1190 {
1191 const VkBufferMemoryBarrier barrier =
1192 {
1193 VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType;
1194 DE_NULL, // const void* pNext;
1195 VK_ACCESS_SHADER_WRITE_BIT, // VkAccessFlags srcAccessMask;
1196 VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask;
1197 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
1198 VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex;
1199 *wd.colorBuffer, // VkBuffer buffer;
1200 0ull, // VkDeviceSize offset;
1201 VK_WHOLE_SIZE, // VkDeviceSize size;
1202 };
1203
1204 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 0,
1205 (const VkMemoryBarrier*)DE_NULL, 1u, &barrier, 0u, (const VkImageMemoryBarrier*)DE_NULL);
1206 }
1207
1208 VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
1209 submitCommandsAndWait(vk, device, SingletonDevice::getUniversalQueue(context), *cmdBuffer);
1210
1211 invalidateMappedMemoryRange(vk, device, wd.colorBufferAlloc->getMemory(), wd.colorBufferAlloc->getOffset(), VK_WHOLE_SIZE);
1212 }
1213
1214 //! Get a single-sampled image access from a multisampled color buffer with samples packed per pixel
getSingleSampledAccess(const void * const imageData,const TestParams & params,const deUint32 sampleNdx,const deUint32 layerNdx)1215 tcu::ConstPixelBufferAccess getSingleSampledAccess (const void* const imageData, const TestParams& params, const deUint32 sampleNdx, const deUint32 layerNdx)
1216 {
1217 const deUint32 numSamples = static_cast<deUint32>(params.numColorSamples);
1218 const deUint32 pixelSize = tcu::getPixelSize(mapVkFormat(params.colorFormat));
1219 const deUint32 rowSize = pixelSize * params.renderSize.x();
1220 const deUint32 layerSize = rowSize * params.renderSize.y();
1221 const deUint8* src = static_cast<const deUint8*>(imageData)
1222 + (layerNdx * numSamples * layerSize)
1223 + (sampleNdx * pixelSize);
1224 const tcu::IVec3 size (params.renderSize.x(), params.renderSize.y(), 1);
1225 const tcu::IVec3 pitch (numSamples * pixelSize,
1226 numSamples * rowSize,
1227 numSamples * layerSize);
1228 return tcu::ConstPixelBufferAccess(mapVkFormat(params.colorFormat), size, pitch, src);
1229 }
1230
test(Context & context,const TestParams params)1231 tcu::TestStatus test (Context& context, const TestParams params)
1232 {
1233 WorkingData wd;
1234 const DeviceInterface& vk = SingletonDevice::getDeviceInterface(context);
1235 const VkDevice device = SingletonDevice::getDevice(context);
1236
1237 MovePtr<Allocator> allocator = MovePtr<Allocator>(new SimpleAllocator(vk, device, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice())));
1238
1239 // Initialize resources
1240 {
1241 const VkImageUsageFlags msImageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
1242 | VK_IMAGE_USAGE_SAMPLED_BIT
1243 | (params.sampleSource == SAMPLE_SOURCE_SUBPASS_INPUT ? VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT : (VkImageUsageFlagBits)0);
1244 wd.colorImage = makeImage(vk, device, params.colorFormat, params.renderSize, params.numLayers, params.numColorSamples, msImageUsage);
1245 wd.colorImageAlloc = bindImage(vk, device, *allocator, *wd.colorImage, MemoryRequirement::Any);
1246 wd.colorImageView = makeImageView(vk, device, *wd.colorImage, (params.numLayers == 1u ? VK_IMAGE_VIEW_TYPE_2D : VK_IMAGE_VIEW_TYPE_2D_ARRAY), params.colorFormat,
1247 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, params.numLayers));
1248
1249 wd.defaultSampler = makeSampler(vk, device);
1250
1251 // Color buffer is meant to hold data for all layers and all samples of the image.
1252 // Data is tightly packed layer by layer, for each pixel all samples are laid out together starting with sample 0.
1253 // E.g.: pixel(0,0)sample(0)sample(1), pixel(1,0)sample(0)sample(1), ...
1254 wd.colorBufferSize = static_cast<VkDeviceSize>(tcu::getPixelSize(mapVkFormat(params.colorFormat))
1255 * params.renderSize.x() * params.renderSize.y() * params.numLayers * static_cast<deUint32>(params.numColorSamples));
1256 wd.colorBuffer = makeBuffer(vk, device, wd.colorBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
1257 wd.colorBufferAlloc = bindBuffer(vk, device, *allocator, *wd.colorBuffer, MemoryRequirement::HostVisible);
1258
1259 deMemset(wd.colorBufferAlloc->getHostPtr(), 0, static_cast<std::size_t>(wd.colorBufferSize));
1260 flushMappedMemoryRange(vk, device, wd.colorBufferAlloc->getMemory(), wd.colorBufferAlloc->getOffset(), VK_WHOLE_SIZE);
1261
1262 const std::vector<PositionColor> vertices = genShapes(params.colorFormat);
1263 const VkDeviceSize vertexBufferSize = static_cast<VkDeviceSize>(sizeof(vertices[0]) * vertices.size());
1264
1265 wd.numVertices = static_cast<deUint32>(vertices.size());
1266 wd.vertexBuffer = makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
1267 wd.vertexBufferAlloc = bindBuffer(vk, device, *allocator, *wd.vertexBuffer, MemoryRequirement::HostVisible);
1268
1269 deMemcpy(wd.vertexBufferAlloc->getHostPtr(), dataOrNullPtr(vertices), static_cast<std::size_t>(vertexBufferSize));
1270 flushMappedMemoryRange(vk, device, wd.vertexBufferAlloc->getMemory(), wd.vertexBufferAlloc->getOffset(), VK_WHOLE_SIZE);
1271 }
1272
1273 if (params.sampleSource == SAMPLE_SOURCE_SUBPASS_INPUT)
1274 {
1275 // Create a multisample image and sample from it
1276 drawAndSampleInputAttachment (context, params, wd);
1277 }
1278 else
1279 {
1280 // Draw the image, then sample from it in a CS
1281 draw (context, params, wd);
1282 dispatchSampleImage (context, params, wd, "comp_fmask_fetch");
1283 }
1284
1285 // Copy the result
1286 std::vector<deUint8> fmaskFetchColorBuffer (static_cast<deUint32>(wd.colorBufferSize));
1287 deMemcpy(&fmaskFetchColorBuffer[0], wd.colorBufferAlloc->getHostPtr(), static_cast<std::size_t>(wd.colorBufferSize));
1288
1289 // Clear the color buffer, just to be sure we're getting the new data
1290 deMemset(wd.colorBufferAlloc->getHostPtr(), 0, static_cast<std::size_t>(wd.colorBufferSize));
1291 flushMappedMemoryRange(vk, device, wd.colorBufferAlloc->getMemory(), wd.colorBufferAlloc->getOffset(), VK_WHOLE_SIZE);
1292
1293 // Sample image using the standard texel fetch
1294 dispatchSampleImage (context, params, wd, "comp_fetch");
1295
1296 // Verify the images
1297 {
1298 const void* const fmaskResult = dataOrNullPtr(fmaskFetchColorBuffer);
1299 const void* const expectedResult = wd.colorBufferAlloc->getHostPtr();
1300
1301 DE_ASSERT(!isFloatFormat(params.colorFormat)); // we're using int compare
1302
1303 // Mismatch, do image compare to pinpoint the failure
1304 for (deUint32 layerNdx = 0u; layerNdx < params.numLayers; ++layerNdx)
1305 for (deUint32 sampleNdx = 0u; sampleNdx < static_cast<deUint32>(params.numColorSamples); ++sampleNdx)
1306 {
1307 const std::string imageName = "layer_" + de::toString(layerNdx) + "_sample_" + de::toString(sampleNdx);
1308 const std::string imageDesc = "Layer " + de::toString(layerNdx) + " Sample " + de::toString(sampleNdx);
1309 const tcu::ConstPixelBufferAccess expected = getSingleSampledAccess(expectedResult, params, sampleNdx, layerNdx);
1310 const tcu::ConstPixelBufferAccess actual = getSingleSampledAccess(fmaskResult, params, sampleNdx, layerNdx);
1311 const UVec4 threshold (0); // should match exactly
1312
1313 const bool ok = tcu::intThresholdCompare(context.getTestContext().getLog(), imageName.c_str(), imageDesc.c_str(),
1314 expected, actual, threshold, tcu::COMPARE_LOG_RESULT);
1315
1316 if (!ok)
1317 return tcu::TestStatus::fail("Some texels were incorrect");
1318 }
1319 }
1320
1321 return tcu::TestStatus::pass("Pass");
1322 }
1323
getFormatShortString(const VkFormat format)1324 std::string getFormatShortString (const VkFormat format)
1325 {
1326 std::string s(de::toLower(getFormatName(format)));
1327 return s.substr(10);
1328 }
1329
createShaderFragmentMaskTestsInGroup(tcu::TestCaseGroup * rootGroup,PipelineConstructionType pipelineConstructionType)1330 void createShaderFragmentMaskTestsInGroup (tcu::TestCaseGroup* rootGroup, PipelineConstructionType pipelineConstructionType)
1331 {
1332 // Per spec, the following formats must support color attachment and sampled image
1333 const VkFormat colorFormats[] =
1334 {
1335 VK_FORMAT_R8G8B8A8_UNORM,
1336 VK_FORMAT_R32_UINT,
1337 VK_FORMAT_R32_SINT,
1338 };
1339
1340 const VkSampleCountFlagBits sampleCounts[] =
1341 {
1342 VK_SAMPLE_COUNT_2_BIT,
1343 VK_SAMPLE_COUNT_4_BIT,
1344 VK_SAMPLE_COUNT_8_BIT,
1345 VK_SAMPLE_COUNT_16_BIT,
1346 };
1347
1348 const struct SourceCase
1349 {
1350 const char* name;
1351 deUint32 numLayers;
1352 SampleSource sampleSource;
1353 } sourceCases[] =
1354 {
1355 { "image_2d", 1u, SAMPLE_SOURCE_IMAGE },
1356 { "image_2d_array", 3u, SAMPLE_SOURCE_IMAGE },
1357 { "subpass_input", 1u, SAMPLE_SOURCE_SUBPASS_INPUT },
1358 };
1359
1360 // Test 1: Compare fragments fetched via FMASK and an ordinary texel fetch
1361 {
1362 for (const VkSampleCountFlagBits* pSampleCount = sampleCounts; pSampleCount != DE_ARRAY_END(sampleCounts); ++pSampleCount)
1363 {
1364 MovePtr<tcu::TestCaseGroup> sampleCountGroup (new tcu::TestCaseGroup(rootGroup->getTestContext(), ("samples_" + de::toString(*pSampleCount)).c_str()));
1365 for (const SourceCase* pSourceCase = sourceCases; pSourceCase != DE_ARRAY_END(sourceCases); ++pSourceCase)
1366 {
1367 // Input attachments cannot be used with dynamic rendering.
1368 if (pSourceCase->sampleSource == SAMPLE_SOURCE_SUBPASS_INPUT && isConstructionTypeShaderObject(pipelineConstructionType))
1369 continue;
1370
1371 MovePtr<tcu::TestCaseGroup> sourceGroup (new tcu::TestCaseGroup(rootGroup->getTestContext(), pSourceCase->name));
1372 for (const VkFormat* pColorFormat = colorFormats; pColorFormat != DE_ARRAY_END(colorFormats); ++pColorFormat)
1373 {
1374 TestParams params;
1375 params.pipelineConstructionType = pipelineConstructionType;
1376 params.renderSize = UVec2(32, 32);
1377 params.colorFormat = *pColorFormat;
1378 params.numColorSamples = *pSampleCount;
1379 params.numLayers = pSourceCase->numLayers;
1380 params.sampleSource = pSourceCase->sampleSource;
1381
1382 addFunctionCaseWithPrograms(sourceGroup.get(), getFormatShortString(*pColorFormat), checkRequirements, initPrograms, test, params);
1383 }
1384 sampleCountGroup->addChild(sourceGroup.release());
1385 }
1386 rootGroup->addChild(sampleCountGroup.release());
1387 }
1388 }
1389 }
1390
1391 } // anonymous ns
1392
createMultisampleShaderFragmentMaskTests(tcu::TestContext & testCtx,PipelineConstructionType pipelineConstructionType)1393 tcu::TestCaseGroup* createMultisampleShaderFragmentMaskTests (tcu::TestContext& testCtx, PipelineConstructionType pipelineConstructionType)
1394 {
1395 const auto cleanGroup = [](tcu::TestCaseGroup*, PipelineConstructionType) { SingletonDevice::destroy(); };
1396 const char* groupName = "shader_fragment_mask";
1397
1398 // Access raw texel values in a compressed MSAA surface
1399 return createTestGroup(testCtx, groupName, createShaderFragmentMaskTestsInGroup, pipelineConstructionType, cleanGroup);
1400 }
1401
1402 } // pipeline
1403 } // vkt
1404