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