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 &params, 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 &params, 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 &params, 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 &params,
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