1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 The Khronos Group Inc.
6  * Copyright (c) 2023 LunarG, Inc.
7  * Copyright (c) 2023 Nintendo
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  *//*!
22  * \file
23  * \brief Multisample image Tests
24  *//*--------------------------------------------------------------------*/
25 
26 #include "vktPipelineMultisampleImageTests.hpp"
27 #include "vktPipelineMakeUtil.hpp"
28 #include "vktTestCase.hpp"
29 #include "vktTestCaseUtil.hpp"
30 #include "vktPipelineVertexUtil.hpp"
31 #include "vktTestGroupUtil.hpp"
32 
33 #include "vkMemUtil.hpp"
34 #include "vkQueryUtil.hpp"
35 #include "vkTypeUtil.hpp"
36 #include "vkRefUtil.hpp"
37 #include "vkBuilderUtil.hpp"
38 #include "vkPrograms.hpp"
39 #include "vkImageUtil.hpp"
40 #include "vkCmdUtil.hpp"
41 #include "vkObjUtil.hpp"
42 
43 #include "tcuTextureUtil.hpp"
44 #include "tcuTestLog.hpp"
45 
46 #include "deUniquePtr.hpp"
47 #include "deSharedPtr.hpp"
48 
49 #include <string>
50 
51 namespace vkt
52 {
53 namespace pipeline
54 {
55 namespace
56 {
57 using namespace vk;
58 using de::MovePtr;
59 using de::SharedPtr;
60 using de::UniquePtr;
61 using tcu::IVec2;
62 using tcu::Vec4;
63 
64 typedef SharedPtr<Unique<VkImageView>> ImageViewSp;
65 typedef SharedPtr<Unique<VkPipeline>> PipelineSp;
66 
67 //! Test case parameters
68 struct CaseDef
69 {
70     PipelineConstructionType pipelineConstructionType;
71     IVec2 renderSize;
72     int numLayers;
73     VkFormat colorFormat;
74     VkSampleCountFlagBits numSamples;
75     bool colorSamples;
76 };
77 
78 template <typename T>
makeSharedPtr(Move<T> move)79 inline SharedPtr<Unique<T>> makeSharedPtr(Move<T> move)
80 {
81     return SharedPtr<Unique<T>>(new Unique<T>(move));
82 }
83 
84 template <typename T>
sizeInBytes(const std::vector<T> & vec)85 inline VkDeviceSize sizeInBytes(const std::vector<T> &vec)
86 {
87     return vec.size() * sizeof(vec[0]);
88 }
89 
90 //! Create a vector of derived pipelines, each with an increasing subpass index
makeGraphicsPipelines(const DeviceInterface & vk,const VkDevice device,const uint32_t numSubpasses,const VkPipelineLayout pipelineLayout,const VkRenderPass renderPass,const ShaderWrapper vertexModule,const ShaderWrapper fragmentModule,const IVec2 renderSize,const VkSampleCountFlagBits numSamples,const VkPrimitiveTopology topology)91 std::vector<PipelineSp> makeGraphicsPipelines(const DeviceInterface &vk, const VkDevice device,
92                                               const uint32_t numSubpasses, const VkPipelineLayout pipelineLayout,
93                                               const VkRenderPass renderPass, const ShaderWrapper vertexModule,
94                                               const ShaderWrapper fragmentModule, const IVec2 renderSize,
95                                               const VkSampleCountFlagBits numSamples,
96                                               const VkPrimitiveTopology topology)
97 {
98     const VkVertexInputBindingDescription vertexInputBindingDescription = {
99         0u,                          // uint32_t binding;
100         sizeof(Vertex4RGBA),         // uint32_t stride;
101         VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate;
102     };
103 
104     const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] = {
105         {
106             0u,                            // uint32_t location;
107             0u,                            // uint32_t binding;
108             VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
109             0u,                            // uint32_t offset;
110         },
111         {
112             1u,                            // uint32_t location;
113             0u,                            // uint32_t binding;
114             VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
115             sizeof(Vec4),                  // uint32_t offset;
116         },
117     };
118 
119     const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo = {
120         VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType                             sType;
121         DE_NULL,                                                   // const void*                                 pNext;
122         (VkPipelineVertexInputStateCreateFlags)0,                  // VkPipelineVertexInputStateCreateFlags       flags;
123         1u,                             // uint32_t                                    vertexBindingDescriptionCount;
124         &vertexInputBindingDescription, // const VkVertexInputBindingDescription*      pVertexBindingDescriptions;
125         DE_LENGTH_OF_ARRAY(
126             vertexInputAttributeDescriptions), // uint32_t                                    vertexAttributeDescriptionCount;
127         vertexInputAttributeDescriptions, // const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions;
128     };
129 
130     const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo = {
131         VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType                             sType;
132         DE_NULL,                                    // const void*                                 pNext;
133         (VkPipelineInputAssemblyStateCreateFlags)0, // VkPipelineInputAssemblyStateCreateFlags     flags;
134         topology,                                   // VkPrimitiveTopology                         topology;
135         VK_FALSE, // VkBool32                                    primitiveRestartEnable;
136     };
137 
138     const VkViewport viewport = makeViewport(renderSize);
139     const VkRect2D scissor    = makeRect2D(renderSize);
140 
141     const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo = {
142         VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType                             sType;
143         DE_NULL,                                               // const void*                                 pNext;
144         (VkPipelineViewportStateCreateFlags)0,                 // VkPipelineViewportStateCreateFlags          flags;
145         1u,        // uint32_t                                    viewportCount;
146         &viewport, // const VkViewport*                           pViewports;
147         1u,        // uint32_t                                    scissorCount;
148         &scissor,  // const VkRect2D*                             pScissors;
149     };
150 
151     const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo = {
152         VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType                          sType;
153         DE_NULL,                                                    // const void*                              pNext;
154         (VkPipelineRasterizationStateCreateFlags)0,                 // VkPipelineRasterizationStateCreateFlags  flags;
155         VK_FALSE,                        // VkBool32                                 depthClampEnable;
156         VK_FALSE,                        // VkBool32                                 rasterizerDiscardEnable;
157         VK_POLYGON_MODE_FILL,            // VkPolygonMode polygonMode;
158         VK_CULL_MODE_NONE,               // VkCullModeFlags cullMode;
159         VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace;
160         VK_FALSE,                        // VkBool32 depthBiasEnable;
161         0.0f,                            // float depthBiasConstantFactor;
162         0.0f,                            // float depthBiasClamp;
163         0.0f,                            // float depthBiasSlopeFactor;
164         1.0f,                            // float lineWidth;
165     };
166 
167     const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo = {
168         VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
169         DE_NULL,                                                  // const void* pNext;
170         (VkPipelineMultisampleStateCreateFlags)0,                 // VkPipelineMultisampleStateCreateFlags flags;
171         numSamples,                                               // VkSampleCountFlagBits rasterizationSamples;
172         VK_FALSE,                                                 // VkBool32 sampleShadingEnable;
173         0.0f,                                                     // float minSampleShading;
174         DE_NULL,                                                  // const VkSampleMask* pSampleMask;
175         VK_FALSE,                                                 // VkBool32 alphaToCoverageEnable;
176         VK_FALSE                                                  // VkBool32 alphaToOneEnable;
177     };
178 
179     const VkStencilOpState stencilOpState = makeStencilOpState(VK_STENCIL_OP_KEEP,   // stencil fail
180                                                                VK_STENCIL_OP_KEEP,   // depth & stencil pass
181                                                                VK_STENCIL_OP_KEEP,   // depth only fail
182                                                                VK_COMPARE_OP_ALWAYS, // compare op
183                                                                0u,                   // compare mask
184                                                                0u,                   // write mask
185                                                                0u);                  // reference
186 
187     VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo = {
188         VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
189         DE_NULL,                                                    // const void* pNext;
190         (VkPipelineDepthStencilStateCreateFlags)0,                  // VkPipelineDepthStencilStateCreateFlags flags;
191         VK_FALSE,                                                   // VkBool32 depthTestEnable;
192         VK_FALSE,                                                   // VkBool32 depthWriteEnable;
193         VK_COMPARE_OP_LESS,                                         // VkCompareOp depthCompareOp;
194         VK_FALSE,                                                   // VkBool32 depthBoundsTestEnable;
195         VK_FALSE,                                                   // VkBool32 stencilTestEnable;
196         stencilOpState,                                             // VkStencilOpState front;
197         stencilOpState,                                             // VkStencilOpState back;
198         0.0f,                                                       // float minDepthBounds;
199         1.0f,                                                       // float maxDepthBounds;
200     };
201 
202     const VkColorComponentFlags colorComponentsAll =
203         VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
204     // Number of blend attachments must equal the number of color attachments during any subpass.
205     const VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState = {
206         VK_FALSE,             // VkBool32 blendEnable;
207         VK_BLEND_FACTOR_ONE,  // VkBlendFactor srcColorBlendFactor;
208         VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor;
209         VK_BLEND_OP_ADD,      // VkBlendOp colorBlendOp;
210         VK_BLEND_FACTOR_ONE,  // VkBlendFactor srcAlphaBlendFactor;
211         VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor;
212         VK_BLEND_OP_ADD,      // VkBlendOp alphaBlendOp;
213         colorComponentsAll,   // VkColorComponentFlags colorWriteMask;
214     };
215 
216     const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo = {
217         VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
218         DE_NULL,                                                  // const void* pNext;
219         (VkPipelineColorBlendStateCreateFlags)0,                  // VkPipelineColorBlendStateCreateFlags flags;
220         VK_FALSE,                                                 // VkBool32 logicOpEnable;
221         VK_LOGIC_OP_COPY,                                         // VkLogicOp logicOp;
222         1u,                                                       // uint32_t attachmentCount;
223         &pipelineColorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
224         {0.0f, 0.0f, 0.0f, 0.0f},           // float blendConstants[4];
225     };
226 
227     const VkPipelineShaderStageCreateInfo pShaderStages[] = {
228         {
229             VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
230             DE_NULL,                                             // const void* pNext;
231             (VkPipelineShaderStageCreateFlags)0,                 // VkPipelineShaderStageCreateFlags flags;
232             VK_SHADER_STAGE_VERTEX_BIT,                          // VkShaderStageFlagBits stage;
233             vertexModule.getModule(),                            // VkShaderModule module;
234             "main",                                              // const char* pName;
235             DE_NULL,                                             // const VkSpecializationInfo* pSpecializationInfo;
236         },
237         {
238             VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
239             DE_NULL,                                             // const void* pNext;
240             (VkPipelineShaderStageCreateFlags)0,                 // VkPipelineShaderStageCreateFlags flags;
241             VK_SHADER_STAGE_FRAGMENT_BIT,                        // VkShaderStageFlagBits stage;
242             fragmentModule.getModule(),                          // VkShaderModule module;
243             "main",                                              // const char* pName;
244             DE_NULL,                                             // const VkSpecializationInfo* pSpecializationInfo;
245         }};
246 
247     DE_ASSERT(numSubpasses > 0u);
248 
249     std::vector<VkGraphicsPipelineCreateInfo> graphicsPipelineInfos(0);
250     std::vector<VkPipeline> rawPipelines(numSubpasses, DE_NULL);
251 
252     {
253 #ifndef CTS_USES_VULKANSC
254         const VkPipelineCreateFlags firstPipelineFlags =
255             (numSubpasses > 1u ? VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT : VkPipelineCreateFlagBits(0));
256 #else
257         const VkPipelineCreateFlags firstPipelineFlags = VkPipelineCreateFlagBits(0);
258 #endif // CTS_USES_VULKANSC
259 
260         VkGraphicsPipelineCreateInfo createInfo = {
261             VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType;
262             DE_NULL,                                         // const void* pNext;
263             firstPipelineFlags,                              // VkPipelineCreateFlags flags;
264             DE_LENGTH_OF_ARRAY(pShaderStages),               // uint32_t stageCount;
265             pShaderStages,                                   // const VkPipelineShaderStageCreateInfo* pStages;
266             &vertexInputStateInfo,           // const VkPipelineVertexInputStateCreateInfo* pVertexInputState;
267             &pipelineInputAssemblyStateInfo, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState;
268             DE_NULL,                         // const VkPipelineTessellationStateCreateInfo* pTessellationState;
269             &pipelineViewportStateInfo,      // const VkPipelineViewportStateCreateInfo* pViewportState;
270             &pipelineRasterizationStateInfo, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState;
271             &pipelineMultisampleStateInfo,   // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
272             &pipelineDepthStencilStateInfo,  // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState;
273             &pipelineColorBlendStateInfo,    // const VkPipelineColorBlendStateCreateInfo* pColorBlendState;
274             DE_NULL,                         // const VkPipelineDynamicStateCreateInfo* pDynamicState;
275             pipelineLayout,                  // VkPipelineLayout layout;
276             renderPass,                      // VkRenderPass renderPass;
277             0u,                              // uint32_t subpass;
278             DE_NULL,                         // VkPipeline basePipelineHandle;
279             0u,                              // int32_t basePipelineIndex;
280         };
281 
282         graphicsPipelineInfos.push_back(createInfo);
283 
284 #ifndef CTS_USES_VULKANSC
285         createInfo.flags             = VK_PIPELINE_CREATE_DERIVATIVE_BIT;
286         createInfo.basePipelineIndex = 0;
287 #endif // CTS_USES_VULKANSC
288 
289         for (uint32_t subpassNdx = 1u; subpassNdx < numSubpasses; ++subpassNdx)
290         {
291             createInfo.subpass = subpassNdx;
292             graphicsPipelineInfos.push_back(createInfo);
293         }
294     }
295 
296     VK_CHECK(vk.createGraphicsPipelines(device, DE_NULL, static_cast<uint32_t>(graphicsPipelineInfos.size()),
297                                         &graphicsPipelineInfos[0], DE_NULL, &rawPipelines[0]));
298 
299     std::vector<PipelineSp> pipelines;
300 
301     for (std::vector<VkPipeline>::const_iterator it = rawPipelines.begin(); it != rawPipelines.end(); ++it)
302         pipelines.push_back(
303             makeSharedPtr(Move<VkPipeline>(check<VkPipeline>(*it), Deleter<VkPipeline>(vk, device, DE_NULL))));
304 
305     return pipelines;
306 }
307 
308 //! Create a vector of pipelines, each with an increasing subpass index
preparePipelineWrapper(GraphicsPipelineWrapper & gpw,const uint32_t subpassNdx,const PipelineLayoutWrapper & pipelineLayout,const VkRenderPass renderPass,const ShaderWrapper vertexModule,const ShaderWrapper fragmentModule,const IVec2 renderSize,const VkSampleCountFlagBits numSamples,const VkPrimitiveTopology topology)309 void preparePipelineWrapper(GraphicsPipelineWrapper &gpw, const uint32_t subpassNdx,
310                             const PipelineLayoutWrapper &pipelineLayout, const VkRenderPass renderPass,
311                             const ShaderWrapper vertexModule, const ShaderWrapper fragmentModule,
312                             const IVec2 renderSize, const VkSampleCountFlagBits numSamples,
313                             const VkPrimitiveTopology topology)
314 {
315     const VkVertexInputBindingDescription vertexInputBindingDescription = {
316         0u,                          // uint32_t binding;
317         sizeof(Vertex4RGBA),         // uint32_t stride;
318         VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate;
319     };
320 
321     const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] = {
322         {
323             0u,                            // uint32_t location;
324             0u,                            // uint32_t binding;
325             VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
326             0u,                            // uint32_t offset;
327         },
328         {
329             1u,                            // uint32_t location;
330             0u,                            // uint32_t binding;
331             VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
332             sizeof(Vec4),                  // uint32_t offset;
333         },
334     };
335 
336     const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo = {
337         VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType                             sType;
338         DE_NULL,                                                   // const void*                                 pNext;
339         (VkPipelineVertexInputStateCreateFlags)0,                  // VkPipelineVertexInputStateCreateFlags       flags;
340         1u,                             // uint32_t                                    vertexBindingDescriptionCount;
341         &vertexInputBindingDescription, // const VkVertexInputBindingDescription*      pVertexBindingDescriptions;
342         DE_LENGTH_OF_ARRAY(
343             vertexInputAttributeDescriptions), // uint32_t                                    vertexAttributeDescriptionCount;
344         vertexInputAttributeDescriptions, // const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions;
345     };
346 
347     const std::vector<VkViewport> viewport{makeViewport(renderSize)};
348     const std::vector<VkRect2D> scissor{makeRect2D(renderSize)};
349 
350     const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo = {
351         VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
352         DE_NULL,                                                  // const void* pNext;
353         (VkPipelineMultisampleStateCreateFlags)0,                 // VkPipelineMultisampleStateCreateFlags flags;
354         numSamples,                                               // VkSampleCountFlagBits rasterizationSamples;
355         VK_FALSE,                                                 // VkBool32 sampleShadingEnable;
356         0.0f,                                                     // float minSampleShading;
357         DE_NULL,                                                  // const VkSampleMask* pSampleMask;
358         VK_FALSE,                                                 // VkBool32 alphaToCoverageEnable;
359         VK_FALSE                                                  // VkBool32 alphaToOneEnable;
360     };
361 
362     const VkColorComponentFlags colorComponentsAll =
363         VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
364     // Number of blend attachments must equal the number of color attachments during any subpass.
365     const VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState = {
366         VK_FALSE,             // VkBool32 blendEnable;
367         VK_BLEND_FACTOR_ONE,  // VkBlendFactor srcColorBlendFactor;
368         VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor;
369         VK_BLEND_OP_ADD,      // VkBlendOp colorBlendOp;
370         VK_BLEND_FACTOR_ONE,  // VkBlendFactor srcAlphaBlendFactor;
371         VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor;
372         VK_BLEND_OP_ADD,      // VkBlendOp alphaBlendOp;
373         colorComponentsAll,   // VkColorComponentFlags colorWriteMask;
374     };
375 
376     const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo = {
377         VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
378         DE_NULL,                                                  // const void* pNext;
379         (VkPipelineColorBlendStateCreateFlags)0,                  // VkPipelineColorBlendStateCreateFlags flags;
380         VK_FALSE,                                                 // VkBool32 logicOpEnable;
381         VK_LOGIC_OP_COPY,                                         // VkLogicOp logicOp;
382         1u,                                                       // uint32_t attachmentCount;
383         &pipelineColorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
384         {0.0f, 0.0f, 0.0f, 0.0f},           // float blendConstants[4];
385     };
386 
387     gpw.setDefaultTopology(topology)
388         .setDefaultRasterizationState()
389         .setDefaultDepthStencilState()
390         .setupVertexInputState(&vertexInputStateInfo)
391         .setupPreRasterizationShaderState(viewport, scissor, pipelineLayout, renderPass, subpassNdx, vertexModule)
392         .setupFragmentShaderState(pipelineLayout, renderPass, subpassNdx, fragmentModule, DE_NULL,
393                                   &pipelineMultisampleStateInfo)
394         .setupFragmentOutputState(renderPass, subpassNdx, &pipelineColorBlendStateInfo, &pipelineMultisampleStateInfo)
395         .setMonolithicPipelineLayout(pipelineLayout)
396         .buildPipeline();
397 }
398 
399 //! Make a render pass with one subpass per color attachment and one attachment per image layer.
makeMultisampleRenderPass(const DeviceInterface & vk,const VkDevice device,const PipelineConstructionType pipelineConstructionType,const VkFormat colorFormat,const VkSampleCountFlagBits numSamples,const uint32_t numLayers)400 RenderPassWrapper makeMultisampleRenderPass(const DeviceInterface &vk, const VkDevice device,
401                                             const PipelineConstructionType pipelineConstructionType,
402                                             const VkFormat colorFormat, const VkSampleCountFlagBits numSamples,
403                                             const uint32_t numLayers)
404 {
405     const VkAttachmentDescription colorAttachmentDescription = {
406         (VkAttachmentDescriptionFlags)0,          // VkAttachmentDescriptionFlags flags;
407         colorFormat,                              // VkFormat format;
408         numSamples,                               // VkSampleCountFlagBits samples;
409         VK_ATTACHMENT_LOAD_OP_CLEAR,              // VkAttachmentLoadOp loadOp;
410         VK_ATTACHMENT_STORE_OP_STORE,             // VkAttachmentStoreOp storeOp;
411         VK_ATTACHMENT_LOAD_OP_DONT_CARE,          // VkAttachmentLoadOp stencilLoadOp;
412         VK_ATTACHMENT_STORE_OP_DONT_CARE,         // VkAttachmentStoreOp stencilStoreOp;
413         VK_IMAGE_LAYOUT_UNDEFINED,                // VkImageLayout initialLayout;
414         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
415     };
416     const std::vector<VkAttachmentDescription> attachmentDescriptions(numLayers, colorAttachmentDescription);
417 
418     // Create a subpass for each attachment (each attachement is a layer of an arrayed image).
419 
420     std::vector<VkAttachmentReference> colorAttachmentReferences(numLayers);
421     std::vector<VkSubpassDescription> subpasses;
422 
423     for (uint32_t i = 0; i < numLayers; ++i)
424     {
425         const VkAttachmentReference attachmentRef = {
426             i,                                       // uint32_t attachment;
427             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
428         };
429         colorAttachmentReferences[i] = attachmentRef;
430 
431         const VkSubpassDescription subpassDescription = {
432             (VkSubpassDescriptionFlags)0,    // VkSubpassDescriptionFlags flags;
433             VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
434             0u,                              // uint32_t inputAttachmentCount;
435             DE_NULL,                         // const VkAttachmentReference* pInputAttachments;
436             1u,                              // uint32_t colorAttachmentCount;
437             &colorAttachmentReferences[i],   // const VkAttachmentReference* pColorAttachments;
438             DE_NULL,                         // const VkAttachmentReference* pResolveAttachments;
439             DE_NULL,                         // const VkAttachmentReference* pDepthStencilAttachment;
440             0u,                              // uint32_t preserveAttachmentCount;
441             DE_NULL                          // const uint32_t* pPreserveAttachments;
442         };
443         subpasses.push_back(subpassDescription);
444     }
445 
446     const VkRenderPassCreateInfo renderPassInfo = {
447         VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,            // VkStructureType sType;
448         DE_NULL,                                              // const void* pNext;
449         (VkRenderPassCreateFlags)0,                           // VkRenderPassCreateFlags flags;
450         static_cast<uint32_t>(attachmentDescriptions.size()), // uint32_t attachmentCount;
451         &attachmentDescriptions[0],                           // const VkAttachmentDescription* pAttachments;
452         static_cast<uint32_t>(subpasses.size()),              // uint32_t subpassCount;
453         &subpasses[0],                                        // const VkSubpassDescription* pSubpasses;
454         0u,                                                   // uint32_t dependencyCount;
455         DE_NULL                                               // const VkSubpassDependency* pDependencies;
456     };
457 
458     return RenderPassWrapper(pipelineConstructionType, vk, device, &renderPassInfo);
459 }
460 
461 //! A single-attachment, single-subpass render pass.
makeSimpleRenderPass(const DeviceInterface & vk,const VkDevice device,const PipelineConstructionType pipelineConstructionType,const VkFormat colorFormat)462 RenderPassWrapper makeSimpleRenderPass(const DeviceInterface &vk, const VkDevice device,
463                                        const PipelineConstructionType pipelineConstructionType,
464                                        const VkFormat colorFormat)
465 {
466     const VkAttachmentDescription colorAttachmentDescription = {
467         (VkAttachmentDescriptionFlags)0,          // VkAttachmentDescriptionFlags flags;
468         colorFormat,                              // VkFormat format;
469         VK_SAMPLE_COUNT_1_BIT,                    // VkSampleCountFlagBits samples;
470         VK_ATTACHMENT_LOAD_OP_CLEAR,              // VkAttachmentLoadOp loadOp;
471         VK_ATTACHMENT_STORE_OP_STORE,             // VkAttachmentStoreOp storeOp;
472         VK_ATTACHMENT_LOAD_OP_DONT_CARE,          // VkAttachmentLoadOp stencilLoadOp;
473         VK_ATTACHMENT_STORE_OP_DONT_CARE,         // VkAttachmentStoreOp stencilStoreOp;
474         VK_IMAGE_LAYOUT_UNDEFINED,                // VkImageLayout initialLayout;
475         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
476     };
477 
478     const VkAttachmentReference colorAttachmentRef = {
479         0u,                                      // uint32_t attachment;
480         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
481     };
482 
483     const VkSubpassDescription subpassDescription = {
484         (VkSubpassDescriptionFlags)0,    // VkSubpassDescriptionFlags flags;
485         VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
486         0u,                              // uint32_t inputAttachmentCount;
487         DE_NULL,                         // const VkAttachmentReference* pInputAttachments;
488         1u,                              // uint32_t colorAttachmentCount;
489         &colorAttachmentRef,             // const VkAttachmentReference* pColorAttachments;
490         DE_NULL,                         // const VkAttachmentReference* pResolveAttachments;
491         DE_NULL,                         // const VkAttachmentReference* pDepthStencilAttachment;
492         0u,                              // uint32_t preserveAttachmentCount;
493         DE_NULL                          // const uint32_t* pPreserveAttachments;
494     };
495 
496     const VkRenderPassCreateInfo renderPassInfo = {
497         VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
498         DE_NULL,                                   // const void* pNext;
499         (VkRenderPassCreateFlags)0,                // VkRenderPassCreateFlags flags;
500         1u,                                        // uint32_t attachmentCount;
501         &colorAttachmentDescription,               // const VkAttachmentDescription* pAttachments;
502         1u,                                        // uint32_t subpassCount;
503         &subpassDescription,                       // const VkSubpassDescription* pSubpasses;
504         0u,                                        // uint32_t dependencyCount;
505         DE_NULL                                    // const VkSubpassDependency* pDependencies;
506     };
507 
508     return RenderPassWrapper(pipelineConstructionType, vk, device, &renderPassInfo);
509 }
510 
makeImage(const DeviceInterface & vk,const VkDevice device,const VkFormat format,const IVec2 & size,const uint32_t numLayers,const VkSampleCountFlagBits samples,const VkImageUsageFlags usage)511 Move<VkImage> makeImage(const DeviceInterface &vk, const VkDevice device, const VkFormat format, const IVec2 &size,
512                         const uint32_t numLayers, const VkSampleCountFlagBits samples, const VkImageUsageFlags usage)
513 {
514     const VkImageCreateInfo imageParams = {
515         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
516         DE_NULL,                             // const void* pNext;
517         (VkImageCreateFlags)0,               // VkImageCreateFlags flags;
518         VK_IMAGE_TYPE_2D,                    // VkImageType imageType;
519         format,                              // VkFormat format;
520         makeExtent3D(size.x(), size.y(), 1), // VkExtent3D extent;
521         1u,                                  // uint32_t mipLevels;
522         numLayers,                           // uint32_t arrayLayers;
523         samples,                             // VkSampleCountFlagBits samples;
524         VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling tiling;
525         usage,                               // VkImageUsageFlags usage;
526         VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
527         0u,                                  // uint32_t queueFamilyIndexCount;
528         DE_NULL,                             // const uint32_t* pQueueFamilyIndices;
529         VK_IMAGE_LAYOUT_UNDEFINED,           // VkImageLayout initialLayout;
530     };
531     return createImage(vk, device, &imageParams);
532 }
533 
534 //! Make a simplest sampler.
makeSampler(const DeviceInterface & vk,const VkDevice device)535 Move<VkSampler> makeSampler(const DeviceInterface &vk, const VkDevice device)
536 {
537     const VkSamplerCreateInfo samplerParams = {
538         VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,   // VkStructureType sType;
539         DE_NULL,                                 // const void* pNext;
540         (VkSamplerCreateFlags)0,                 // VkSamplerCreateFlags flags;
541         VK_FILTER_NEAREST,                       // VkFilter magFilter;
542         VK_FILTER_NEAREST,                       // VkFilter minFilter;
543         VK_SAMPLER_MIPMAP_MODE_NEAREST,          // VkSamplerMipmapMode mipmapMode;
544         VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,   // VkSamplerAddressMode addressModeU;
545         VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,   // VkSamplerAddressMode addressModeV;
546         VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,   // VkSamplerAddressMode addressModeW;
547         0.0f,                                    // float mipLodBias;
548         VK_FALSE,                                // VkBool32 anisotropyEnable;
549         1.0f,                                    // float maxAnisotropy;
550         VK_FALSE,                                // VkBool32 compareEnable;
551         VK_COMPARE_OP_ALWAYS,                    // VkCompareOp compareOp;
552         0.0f,                                    // float minLod;
553         0.0f,                                    // float maxLod;
554         VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // VkBorderColor borderColor;
555         VK_FALSE,                                // VkBool32 unnormalizedCoordinates;
556     };
557     return createSampler(vk, device, &samplerParams);
558 }
559 
makeColorSubresourceRange(const int baseArrayLayer,const int layerCount)560 inline VkImageSubresourceRange makeColorSubresourceRange(const int baseArrayLayer, const int layerCount)
561 {
562     return makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, static_cast<uint32_t>(baseArrayLayer),
563                                      static_cast<uint32_t>(layerCount));
564 }
565 
makeColorSubresourceLayers(const int baseArrayLayer,const int layerCount)566 inline VkImageSubresourceLayers makeColorSubresourceLayers(const int baseArrayLayer, const int layerCount)
567 {
568     return makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, static_cast<uint32_t>(baseArrayLayer),
569                                       static_cast<uint32_t>(layerCount));
570 }
571 
checkImageFormatRequirements(const InstanceInterface & vki,const VkPhysicalDevice physDevice,const VkSampleCountFlagBits sampleCount,const VkFormat format,const VkImageUsageFlags usage)572 void checkImageFormatRequirements(const InstanceInterface &vki, const VkPhysicalDevice physDevice,
573                                   const VkSampleCountFlagBits sampleCount, const VkFormat format,
574                                   const VkImageUsageFlags usage)
575 {
576     VkPhysicalDeviceFeatures features;
577     vki.getPhysicalDeviceFeatures(physDevice, &features);
578 
579     if (((usage & VK_IMAGE_USAGE_STORAGE_BIT) != 0) && !features.shaderStorageImageMultisample)
580         TCU_THROW(NotSupportedError, "Multisampled storage images are not supported");
581 
582     VkImageFormatProperties imageFormatProperties;
583     const VkResult imageFormatResult =
584         vki.getPhysicalDeviceImageFormatProperties(physDevice, format, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, usage,
585                                                    (VkImageCreateFlags)0, &imageFormatProperties);
586 
587     if (imageFormatResult == VK_ERROR_FORMAT_NOT_SUPPORTED)
588         TCU_THROW(NotSupportedError, "Image format is not supported");
589 
590     if ((imageFormatProperties.sampleCounts & sampleCount) != sampleCount)
591         TCU_THROW(NotSupportedError, "Requested sample count is not supported");
592 }
593 
594 //! The default foreground color.
getPrimitiveColor(void)595 inline Vec4 getPrimitiveColor(void)
596 {
597     return Vec4(1.0f, 0.0f, 0.0f, 1.0f);
598 }
599 
600 //! Get a reference clear value based on color format.
getClearValue(const VkFormat format)601 VkClearValue getClearValue(const VkFormat format)
602 {
603     if (isUintFormat(format) || isIntFormat(format))
604         return makeClearValueColorU32(16, 32, 64, 96);
605     else
606         return makeClearValueColorF32(0.0f, 0.0f, 1.0f, 1.0f);
607 }
608 
getColorFormatStr(const int numComponents,const bool isUint,const bool isSint)609 std::string getColorFormatStr(const int numComponents, const bool isUint, const bool isSint)
610 {
611     std::ostringstream str;
612     if (numComponents == 1)
613         str << (isUint ? "uint" : isSint ? "int" : "float");
614     else
615         str << (isUint ? "u" : isSint ? "i" : "") << "vec" << numComponents;
616 
617     return str.str();
618 }
619 
getSamplerTypeStr(const int numLayers,const bool isUint,const bool isSint)620 std::string getSamplerTypeStr(const int numLayers, const bool isUint, const bool isSint)
621 {
622     std::ostringstream str;
623     str << (isUint ? "u" : isSint ? "i" : "") << "sampler2DMS" << (numLayers > 1 ? "Array" : "");
624     return str.str();
625 }
626 
627 //! Generate a gvec4 color literal.
628 template <typename T>
getColorStr(const T * data,int numComponents,const bool isUint,const bool isSint)629 std::string getColorStr(const T *data, int numComponents, const bool isUint, const bool isSint)
630 {
631     const int maxIndex = 3; // 4 components max
632 
633     std::ostringstream str;
634     str << (isUint ? "u" : isSint ? "i" : "") << "vec4(";
635 
636     for (int i = 0; i < numComponents; ++i)
637     {
638         str << data[i] << (i < maxIndex ? ", " : "");
639     }
640 
641     for (int i = numComponents; i < maxIndex + 1; ++i)
642     {
643         str << (i == maxIndex ? 1 : 0) << (i < maxIndex ? ", " : "");
644     }
645 
646     str << ")";
647     return str.str();
648 }
649 
650 //! Clear color literal value used by the sampling shader.
getReferenceClearColorStr(const VkFormat format,const int numComponents,const bool isUint,const bool isSint)651 std::string getReferenceClearColorStr(const VkFormat format, const int numComponents, const bool isUint,
652                                       const bool isSint)
653 {
654     const VkClearColorValue clearColor = getClearValue(format).color;
655     if (isUint)
656         return getColorStr(clearColor.uint32, numComponents, isUint, isSint);
657     else if (isSint)
658         return getColorStr(clearColor.int32, numComponents, isUint, isSint);
659     else
660         return getColorStr(clearColor.float32, numComponents, isUint, isSint);
661 }
662 
663 //! Primitive color literal value used by the sampling shader.
getReferencePrimitiveColorStr(int numComponents,const bool isUint,const bool isSint)664 std::string getReferencePrimitiveColorStr(int numComponents, const bool isUint, const bool isSint)
665 {
666     const Vec4 color = getPrimitiveColor();
667     return getColorStr(color.getPtr(), numComponents, isUint, isSint);
668 }
669 
getNumSamples(const VkSampleCountFlagBits samples)670 inline int getNumSamples(const VkSampleCountFlagBits samples)
671 {
672     return static_cast<int>(samples); // enum bitmask actually matches the number of samples
673 }
674 
675 //! A flat-colored shape with sharp angles to make antialiasing visible.
genTriangleVertices(void)676 std::vector<Vertex4RGBA> genTriangleVertices(void)
677 {
678     static const Vertex4RGBA data[] = {
679         {
680             Vec4(-1.0f, 0.0f, 0.0f, 1.0f),
681             getPrimitiveColor(),
682         },
683         {
684             Vec4(0.8f, 0.2f, 0.0f, 1.0f),
685             getPrimitiveColor(),
686         },
687         {
688             Vec4(0.8f, -0.2f, 0.0f, 1.0f),
689             getPrimitiveColor(),
690         },
691     };
692     return std::vector<Vertex4RGBA>(data, data + DE_LENGTH_OF_ARRAY(data));
693 }
694 
sampleIndexToColor(uint32_t index)695 Vec4 sampleIndexToColor(uint32_t index)
696 {
697     Vec4 res = Vec4(0.0f, 0.0f, 0.0f, 1.0f);
698 
699     if (index & 0x01)
700         res += Vec4(0.5f, 0.0f, 0.0f, 0.0f);
701     if (index & 0x02)
702         res += Vec4(0.0f, 0.5f, 0.0f, 0.0f);
703     if (index & 0x04)
704         res += Vec4(0.0f, 0.0f, 0.5f, 0.0f);
705 
706     if (index & 0x08)
707         res += Vec4(0.5f, 0.0f, 0.0f, 0.0f);
708     if (index & 0x10)
709         res += Vec4(0.0f, 0.5f, 0.0f, 0.0f);
710     if (index & 0x20)
711         res += Vec4(0.0f, 0.0f, 0.5f, 0.0f);
712 
713     return res;
714 }
715 
getStandardSampleLocations(VkSampleCountFlagBits samples)716 float *getStandardSampleLocations(VkSampleCountFlagBits samples)
717 {
718     static float standardSampleLocations_1[1 * 2] = {
719         0.5f,
720         0.5f,
721     };
722 
723     static float standardSampleLocations_2[2 * 2] = {
724         0.75f,
725         0.75f,
726         0.25f,
727         0.25f,
728     };
729 
730     static float standardSampleLocations_4[4 * 2] = {
731         0.375f, 0.125f, 0.875f, 0.375f, 0.125f, 0.625f, 0.625f, 0.875f,
732     };
733 
734     static float standardSampleLocations_8[8 * 2] = {
735         0.5625f, 0.3125f, 0.4375f, 0.6875f, 0.8125f, 0.5625f, 0.3125f, 0.1875f,
736         0.1875f, 0.8125f, 0.0625f, 0.4375f, 0.6875f, 0.9375f, 0.9375f, 0.0625f,
737     };
738 
739     static float standardSampleLocations_16[16 * 2] = {
740         0.5625f, 0.5625f, 0.4375f, 0.3125f, 0.3125f, 0.625f, 0.75f,  0.4375f, 0.1875f, 0.375f, 0.625f,
741         0.8125f, 0.8125f, 0.6875f, 0.6875f, 0.1875f, 0.375f, 0.875f, 0.5f,    0.0625f, 0.25f,  0.125f,
742         0.125f,  0.75f,   0.0f,    0.5f,    0.9375f, 0.25f,  0.875f, 0.9375f, 0.0625f, 0.0f,
743     };
744 
745     switch (samples)
746     {
747     case VK_SAMPLE_COUNT_1_BIT:
748         return standardSampleLocations_1;
749     case VK_SAMPLE_COUNT_2_BIT:
750         return standardSampleLocations_2;
751     case VK_SAMPLE_COUNT_4_BIT:
752         return standardSampleLocations_4;
753     case VK_SAMPLE_COUNT_8_BIT:
754         return standardSampleLocations_8;
755     case VK_SAMPLE_COUNT_16_BIT:
756         return standardSampleLocations_16;
757     default:
758         TCU_THROW(InternalError, "Unknown multisample bit configuration requested");
759     }
760 }
761 
762 //! A flat-colored shapes plotted at standard sample points.
genPerSampleTriangleVertices(VkSampleCountFlagBits samples)763 std::vector<Vertex4RGBA> genPerSampleTriangleVertices(VkSampleCountFlagBits samples)
764 {
765     float *coordinates       = getStandardSampleLocations(samples);
766     const float triangleSize = 1.0f / (static_cast<float>(samples) * 2.0f);
767     std::vector<Vertex4RGBA> res;
768 
769     for (uint32_t i = 0; i < static_cast<uint32_t>(samples); i++)
770     {
771         Vertex4RGBA data[] = {
772             {
773                 Vec4(0 + coordinates[i * 2 + 0] * 2 - 1, -triangleSize + coordinates[i * 2 + 1] * 2 - 1, 0.0f, 1.0f),
774                 sampleIndexToColor(i),
775             },
776             {
777                 Vec4(-triangleSize + coordinates[i * 2 + 0] * 2 - 1, triangleSize + coordinates[i * 2 + 1] * 2 - 1,
778                      0.0f, 1.0f),
779                 sampleIndexToColor(i),
780             },
781             {
782                 Vec4(triangleSize + coordinates[i * 2 + 0] * 2 - 1, triangleSize + coordinates[i * 2 + 1] * 2 - 1, 0.0f,
783                      1.0f),
784                 sampleIndexToColor(i),
785             },
786         };
787         res.push_back(data[0]);
788         res.push_back(data[1]);
789         res.push_back(data[2]);
790     }
791     return res;
792 }
793 
794 //! A full-viewport quad. Use with TRIANGLE_STRIP topology.
genFullQuadVertices(void)795 std::vector<Vertex4RGBA> genFullQuadVertices(void)
796 {
797     static const Vertex4RGBA data[] = {
798         {
799             Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
800             Vec4(), // unused
801         },
802         {
803             Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
804             Vec4(), // unused
805         },
806         {
807             Vec4(1.0f, -1.0f, 0.0f, 1.0f),
808             Vec4(), // unused
809         },
810         {
811             Vec4(1.0f, 1.0f, 0.0f, 1.0f),
812             Vec4(), // unused
813         },
814     };
815     return std::vector<Vertex4RGBA>(data, data + DE_LENGTH_OF_ARRAY(data));
816 }
817 
getShaderImageFormatQualifier(const tcu::TextureFormat & format)818 std::string getShaderImageFormatQualifier(const tcu::TextureFormat &format)
819 {
820     const char *orderPart;
821     const char *typePart;
822 
823     switch (format.order)
824     {
825     case tcu::TextureFormat::R:
826         orderPart = "r";
827         break;
828     case tcu::TextureFormat::RG:
829         orderPart = "rg";
830         break;
831     case tcu::TextureFormat::RGB:
832         orderPart = "rgb";
833         break;
834     case tcu::TextureFormat::RGBA:
835         orderPart = "rgba";
836         break;
837 
838     default:
839         DE_ASSERT(false);
840         orderPart = DE_NULL;
841     }
842 
843     switch (format.type)
844     {
845     case tcu::TextureFormat::FLOAT:
846         typePart = "32f";
847         break;
848     case tcu::TextureFormat::HALF_FLOAT:
849         typePart = "16f";
850         break;
851 
852     case tcu::TextureFormat::UNSIGNED_INT32:
853         typePart = "32ui";
854         break;
855     case tcu::TextureFormat::UNSIGNED_INT16:
856         typePart = "16ui";
857         break;
858     case tcu::TextureFormat::UNSIGNED_INT8:
859         typePart = "8ui";
860         break;
861 
862     case tcu::TextureFormat::SIGNED_INT32:
863         typePart = "32i";
864         break;
865     case tcu::TextureFormat::SIGNED_INT16:
866         typePart = "16i";
867         break;
868     case tcu::TextureFormat::SIGNED_INT8:
869         typePart = "8i";
870         break;
871 
872     case tcu::TextureFormat::UNORM_INT16:
873         typePart = "16";
874         break;
875     case tcu::TextureFormat::UNORM_INT8:
876         typePart = "8";
877         break;
878 
879     case tcu::TextureFormat::SNORM_INT16:
880         typePart = "16_snorm";
881         break;
882     case tcu::TextureFormat::SNORM_INT8:
883         typePart = "8_snorm";
884         break;
885 
886     default:
887         DE_ASSERT(false);
888         typePart = DE_NULL;
889     }
890 
891     return std::string() + orderPart + typePart;
892 }
893 
getShaderMultisampledImageType(const tcu::TextureFormat & format,const int numLayers)894 std::string getShaderMultisampledImageType(const tcu::TextureFormat &format, const int numLayers)
895 {
896     const std::string formatPart =
897         tcu::getTextureChannelClass(format.type) == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER ? "u" :
898         tcu::getTextureChannelClass(format.type) == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER   ? "i" :
899                                                                                                 "";
900 
901     std::ostringstream str;
902     str << formatPart << "image2DMS" << (numLayers > 1 ? "Array" : "");
903 
904     return str.str();
905 }
906 
addSimpleVertexAndFragmentPrograms(SourceCollections & programCollection,const CaseDef caseDef)907 void addSimpleVertexAndFragmentPrograms(SourceCollections &programCollection, const CaseDef caseDef)
908 {
909     const int numComponents = tcu::getNumUsedChannels(mapVkFormat(caseDef.colorFormat).order);
910     const bool isUint       = isUintFormat(caseDef.colorFormat);
911     const bool isSint       = isIntFormat(caseDef.colorFormat);
912 
913     // Vertex shader
914     {
915         std::ostringstream src;
916         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
917             << "\n"
918             << "layout(location = 0) in  vec4 in_position;\n"
919             << "layout(location = 1) in  vec4 in_color;\n"
920             << "layout(location = 0) out vec4 o_color;\n"
921             << "\n"
922             << "out gl_PerVertex {\n"
923             << "    vec4 gl_Position;\n"
924             << "};\n"
925             << "\n"
926             << "void main(void)\n"
927             << "{\n"
928             << "    gl_Position = in_position;\n"
929             << "    o_color     = in_color;\n"
930             << "}\n";
931 
932         programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
933     }
934 
935     // Fragment shader
936     {
937         const std::string colorFormat = getColorFormatStr(numComponents, isUint, isSint);
938 
939         std::ostringstream src;
940         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
941             << "\n"
942             << "layout(location = 0) in  vec4 in_color;\n"
943             << "layout(location = 0) out " << colorFormat << " o_color;\n"
944             << "\n"
945             << "void main(void)\n"
946             << "{\n"
947             << "    o_color = " << colorFormat << "(" // float color will be converted to int/uint here if needed
948             << (numComponents == 1 ? "in_color.r" :
949                 numComponents == 2 ? "in_color.rg" :
950                 numComponents == 3 ? "in_color.rgb" :
951                                      "in_color")
952             << ");\n"
953             << "}\n";
954 
955         programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
956     }
957 }
958 
959 //! Synchronously render to a multisampled color image.
renderMultisampledImage(Context & context,const CaseDef & caseDef,const VkImage colorImage)960 void renderMultisampledImage(Context &context, const CaseDef &caseDef, const VkImage colorImage)
961 {
962     const InstanceInterface &vki          = context.getInstanceInterface();
963     const DeviceInterface &vk             = context.getDeviceInterface();
964     const VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
965     const VkDevice device                 = context.getDevice();
966     const VkQueue queue                   = context.getUniversalQueue();
967     const uint32_t queueFamilyIndex       = context.getUniversalQueueFamilyIndex();
968     Allocator &allocator                  = context.getDefaultAllocator();
969 
970     const Unique<VkCommandPool> cmdPool(
971         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
972     const Unique<VkCommandBuffer> cmdBuffer(makeCommandBuffer(vk, device, *cmdPool));
973 
974     {
975         // Create an image view (attachment) for each layer of the image
976         std::vector<ImageViewSp> colorAttachments;
977         std::vector<VkImage> images;
978         std::vector<VkImageView> attachmentHandles;
979         for (int i = 0; i < caseDef.numLayers; ++i)
980         {
981             colorAttachments.push_back(makeSharedPtr(makeImageView(
982                 vk, device, colorImage, VK_IMAGE_VIEW_TYPE_2D, caseDef.colorFormat, makeColorSubresourceRange(i, 1))));
983             images.push_back(colorImage);
984             attachmentHandles.push_back(**colorAttachments.back());
985         }
986 
987         // Vertex buffer
988         const std::vector<Vertex4RGBA> vertices =
989             caseDef.colorSamples ? genPerSampleTriangleVertices(caseDef.numSamples) : genTriangleVertices();
990         const VkDeviceSize vertexBufferSize = sizeInBytes(vertices);
991         const Unique<VkBuffer> vertexBuffer(
992             makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
993         const UniquePtr<Allocation> vertexBufferAlloc(
994             bindBuffer(vk, device, allocator, *vertexBuffer, MemoryRequirement::HostVisible));
995 
996         {
997             deMemcpy(vertexBufferAlloc->getHostPtr(), &vertices[0], static_cast<std::size_t>(vertexBufferSize));
998             flushAlloc(vk, device, *vertexBufferAlloc);
999         }
1000 
1001         const ShaderWrapper vertexModule(ShaderWrapper(vk, device, context.getBinaryCollection().get("vert"), 0u));
1002         const ShaderWrapper fragmentModule(ShaderWrapper(vk, device, context.getBinaryCollection().get("frag"), 0u));
1003         RenderPassWrapper renderPass(makeMultisampleRenderPass(
1004             vk, device, caseDef.pipelineConstructionType, caseDef.colorFormat, caseDef.numSamples, caseDef.numLayers));
1005         renderPass.createFramebuffer(vk, device, caseDef.numLayers, &images[0], &attachmentHandles[0],
1006                                      static_cast<uint32_t>(caseDef.renderSize.x()),
1007                                      static_cast<uint32_t>(caseDef.renderSize.y()));
1008         const PipelineLayoutWrapper pipelineLayout(caseDef.pipelineConstructionType, vk, device);
1009         const bool isMonolithic(caseDef.pipelineConstructionType == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC);
1010         std::vector<PipelineSp> pipelinesSp;
1011         std::vector<GraphicsPipelineWrapper> pipelineWrapper;
1012 
1013         if (isMonolithic)
1014         {
1015             pipelinesSp = makeGraphicsPipelines(vk, device, caseDef.numLayers, *pipelineLayout, *renderPass,
1016                                                 vertexModule, fragmentModule, caseDef.renderSize, caseDef.numSamples,
1017                                                 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
1018         }
1019         else
1020         {
1021             // we can't create a vector of derived pipelines with GraphicsPipelineWrapper
1022             pipelineWrapper.reserve(caseDef.numLayers);
1023             for (int subpassNdx = 0; subpassNdx < caseDef.numLayers; ++subpassNdx)
1024             {
1025                 pipelineWrapper.emplace_back(vki, vk, physicalDevice, device, context.getDeviceExtensions(),
1026                                              caseDef.pipelineConstructionType);
1027                 preparePipelineWrapper(pipelineWrapper.back(), subpassNdx, pipelineLayout, *renderPass, vertexModule,
1028                                        fragmentModule, caseDef.renderSize, caseDef.numSamples,
1029                                        VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
1030             }
1031         }
1032 
1033         beginCommandBuffer(vk, *cmdBuffer);
1034 
1035         const std::vector<VkClearValue> clearValues(caseDef.numLayers, getClearValue(caseDef.colorFormat));
1036 
1037         renderPass.begin(vk, *cmdBuffer, makeRect2D(0, 0, caseDef.renderSize.x(), caseDef.renderSize.y()),
1038                          (uint32_t)clearValues.size(), &clearValues[0]);
1039         {
1040             const VkDeviceSize vertexBufferOffset = 0ull;
1041             vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
1042         }
1043 
1044         for (int layerNdx = 0; layerNdx < caseDef.numLayers; ++layerNdx)
1045         {
1046             if (layerNdx != 0)
1047                 renderPass.nextSubpass(vk, *cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
1048 
1049             if (isMonolithic)
1050                 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, **pipelinesSp[layerNdx]);
1051             else
1052                 pipelineWrapper[layerNdx].bind(*cmdBuffer);
1053             vk.cmdDraw(*cmdBuffer, static_cast<uint32_t>(vertices.size()), 1u, 0u, 0u);
1054         }
1055 
1056         renderPass.end(vk, *cmdBuffer);
1057 
1058         endCommandBuffer(vk, *cmdBuffer);
1059         submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1060     }
1061 }
1062 
1063 namespace SampledImage
1064 {
1065 
initPrograms(SourceCollections & programCollection,const CaseDef caseDef)1066 void initPrograms(SourceCollections &programCollection, const CaseDef caseDef)
1067 {
1068     // Pass 1: Render to texture
1069 
1070     addSimpleVertexAndFragmentPrograms(programCollection, caseDef);
1071 
1072     // Pass 2: Sample texture
1073 
1074     // Vertex shader
1075     {
1076         std::ostringstream src;
1077         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1078             << "\n"
1079             << "layout(location = 0) in  vec4  in_position;\n"
1080             << "\n"
1081             << "out gl_PerVertex {\n"
1082             << "    vec4 gl_Position;\n"
1083             << "};\n"
1084             << "\n"
1085             << "void main(void)\n"
1086             << "{\n"
1087             << "    gl_Position = in_position;\n"
1088             << "}\n";
1089 
1090         programCollection.glslSources.add("sample_vert") << glu::VertexSource(src.str());
1091     }
1092 
1093     // Fragment shader
1094     {
1095         const int numComponents          = tcu::getNumUsedChannels(mapVkFormat(caseDef.colorFormat).order);
1096         const bool isUint                = isUintFormat(caseDef.colorFormat);
1097         const bool isSint                = isIntFormat(caseDef.colorFormat);
1098         const std::string texelFormatStr = (isUint ? "uvec4" : isSint ? "ivec4" : "vec4");
1099         const std::string refClearColor = getReferenceClearColorStr(caseDef.colorFormat, numComponents, isUint, isSint);
1100         const std::string refPrimitiveColor = getReferencePrimitiveColorStr(numComponents, isUint, isSint);
1101         const std::string samplerTypeStr    = getSamplerTypeStr(caseDef.numLayers, isUint, isSint);
1102 
1103         std::ostringstream src;
1104         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1105             << "\n"
1106             << "layout(location = 0) out uvec2 o_status;\n"
1107             << "\n"
1108             << "layout(set = 0, binding = 0) uniform " << samplerTypeStr << " colorTexture;\n"
1109             << "\n"
1110             << "void main(void)\n"
1111             << "{\n"
1112             << "    uint clearColorCount = 0;\n"
1113             << "    uint primitiveColorCount = 0;\n"
1114             << "\n";
1115 
1116         if (caseDef.numLayers == 1)
1117             src << "    for (int sampleNdx = 0; sampleNdx < " << caseDef.numSamples << "; ++sampleNdx) {\n"
1118                 << "        " << texelFormatStr
1119                 << " color = texelFetch(colorTexture, ivec2(gl_FragCoord.xy), sampleNdx);\n"
1120                 << "        if (color == " << refClearColor << ")\n"
1121                 << "            ++clearColorCount;\n"
1122                 << "        else if (color == " << refPrimitiveColor << ")\n"
1123                 << "            ++primitiveColorCount;\n"
1124                 << "    }\n";
1125         else
1126             src << "    for (int layerNdx = 0; layerNdx < " << caseDef.numLayers << "; ++layerNdx)\n"
1127                 << "    for (int sampleNdx = 0; sampleNdx < " << caseDef.numSamples << "; ++sampleNdx) {\n"
1128                 << "        " << texelFormatStr
1129                 << " color = texelFetch(colorTexture, ivec3(gl_FragCoord.xy, layerNdx), sampleNdx);\n"
1130                 << "        if (color == " << refClearColor << ")\n"
1131                 << "            ++clearColorCount;\n"
1132                 << "        else if (color == " << refPrimitiveColor << ")\n"
1133                 << "            ++primitiveColorCount;\n"
1134                 << "    }\n";
1135 
1136         src << "\n"
1137             << "    o_status = uvec2(clearColorCount, primitiveColorCount);\n"
1138             << "}\n";
1139 
1140         programCollection.glslSources.add("sample_frag") << glu::FragmentSource(src.str());
1141     }
1142 }
1143 
checkSupport(Context & context,const CaseDef caseDef)1144 void checkSupport(Context &context, const CaseDef caseDef)
1145 {
1146     const VkImageUsageFlags colorImageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
1147 
1148     checkImageFormatRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), caseDef.numSamples,
1149                                  caseDef.colorFormat, colorImageUsage);
1150     checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
1151                                           caseDef.pipelineConstructionType);
1152 
1153 #ifndef CTS_USES_VULKANSC
1154     if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
1155         !context.getPortabilitySubsetFeatures().multisampleArrayImage &&
1156         (caseDef.numSamples != VK_SAMPLE_COUNT_1_BIT) && (caseDef.numLayers != 1))
1157     {
1158         TCU_THROW(
1159             NotSupportedError,
1160             "VK_KHR_portability_subset: Implementation does not support image array with multiple samples per texel");
1161     }
1162 #endif // CTS_USES_VULKANSC
1163 }
1164 
test(Context & context,const CaseDef caseDef)1165 tcu::TestStatus test(Context &context, const CaseDef caseDef)
1166 {
1167     const InstanceInterface &vki          = context.getInstanceInterface();
1168     const DeviceInterface &vk             = context.getDeviceInterface();
1169     const VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
1170     const VkDevice device                 = context.getDevice();
1171     const VkQueue queue                   = context.getUniversalQueue();
1172     const uint32_t queueFamilyIndex       = context.getUniversalQueueFamilyIndex();
1173     Allocator &allocator                  = context.getDefaultAllocator();
1174 
1175     const VkImageUsageFlags colorImageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
1176 
1177     {
1178         tcu::TestLog &log = context.getTestContext().getLog();
1179         log << tcu::LogSection("Description", "") << tcu::TestLog::Message
1180             << "Rendering to a multisampled image. Expecting all samples to be either a clear color or a primitive "
1181                "color."
1182             << tcu::TestLog::EndMessage << tcu::TestLog::Message
1183             << "Sampling from the texture with texelFetch (OpImageFetch)." << tcu::TestLog::EndMessage
1184             << tcu::TestLog::EndSection;
1185     }
1186 
1187     // Multisampled color image
1188     const Unique<VkImage> colorImage(makeImage(vk, device, caseDef.colorFormat, caseDef.renderSize, caseDef.numLayers,
1189                                                caseDef.numSamples, colorImageUsage));
1190     const UniquePtr<Allocation> colorImageAlloc(bindImage(vk, device, allocator, *colorImage, MemoryRequirement::Any));
1191 
1192     const Unique<VkCommandPool> cmdPool(
1193         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1194     const Unique<VkCommandBuffer> cmdBuffer(makeCommandBuffer(vk, device, *cmdPool));
1195 
1196     // Step 1: Render to texture
1197     {
1198         renderMultisampledImage(context, caseDef, *colorImage);
1199     }
1200 
1201     // Step 2: Sample texture
1202     {
1203         // Color image view
1204         const VkImageViewType colorImageViewType =
1205             (caseDef.numLayers == 1 ? VK_IMAGE_VIEW_TYPE_2D : VK_IMAGE_VIEW_TYPE_2D_ARRAY);
1206         const Unique<VkImageView> colorImageView(makeImageView(vk, device, *colorImage, colorImageViewType,
1207                                                                caseDef.colorFormat,
1208                                                                makeColorSubresourceRange(0, caseDef.numLayers)));
1209         const Unique<VkSampler> colorSampler(makeSampler(vk, device));
1210 
1211         // Checksum image
1212         const VkFormat checksumFormat = VK_FORMAT_R8G8_UINT;
1213         const Unique<VkImage> checksumImage(
1214             makeImage(vk, device, checksumFormat, caseDef.renderSize, 1u, VK_SAMPLE_COUNT_1_BIT,
1215                       VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT));
1216         const UniquePtr<Allocation> checksumImageAlloc(
1217             bindImage(vk, device, allocator, *checksumImage, MemoryRequirement::Any));
1218         const Unique<VkImageView> checksumImageView(makeImageView(vk, device, *checksumImage, VK_IMAGE_VIEW_TYPE_2D,
1219                                                                   checksumFormat, makeColorSubresourceRange(0, 1)));
1220 
1221         // Checksum buffer (for host reading)
1222         const VkDeviceSize checksumBufferSize =
1223             caseDef.renderSize.x() * caseDef.renderSize.y() * tcu::getPixelSize(mapVkFormat(checksumFormat));
1224         const Unique<VkBuffer> checksumBuffer(
1225             makeBuffer(vk, device, checksumBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
1226         const UniquePtr<Allocation> checksumBufferAlloc(
1227             bindBuffer(vk, device, allocator, *checksumBuffer, MemoryRequirement::HostVisible));
1228 
1229         zeroBuffer(vk, device, *checksumBufferAlloc, checksumBufferSize);
1230 
1231         // Vertex buffer
1232         const std::vector<Vertex4RGBA> vertices = genFullQuadVertices();
1233         const VkDeviceSize vertexBufferSize     = sizeInBytes(vertices);
1234         const Unique<VkBuffer> vertexBuffer(
1235             makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
1236         const UniquePtr<Allocation> vertexBufferAlloc(
1237             bindBuffer(vk, device, allocator, *vertexBuffer, MemoryRequirement::HostVisible));
1238 
1239         {
1240             deMemcpy(vertexBufferAlloc->getHostPtr(), &vertices[0], static_cast<std::size_t>(vertexBufferSize));
1241             flushAlloc(vk, device, *vertexBufferAlloc);
1242         }
1243 
1244         // Descriptors
1245         // \note OpImageFetch doesn't use a sampler, but in GLSL texelFetch needs a sampler2D which translates to a combined image sampler in Vulkan.
1246 
1247         const Unique<VkDescriptorSetLayout> descriptorSetLayout(
1248             DescriptorSetLayoutBuilder()
1249                 .addSingleSamplerBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT,
1250                                          &colorSampler.get())
1251                 .build(vk, device));
1252 
1253         const Unique<VkDescriptorPool> descriptorPool(
1254             DescriptorPoolBuilder()
1255                 .addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
1256                 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
1257 
1258         const Unique<VkDescriptorSet> descriptorSet(
1259             makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
1260         const VkDescriptorImageInfo imageDescriptorInfo =
1261             makeDescriptorImageInfo(DE_NULL, *colorImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
1262 
1263         DescriptorSetUpdateBuilder()
1264             .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
1265                          VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageDescriptorInfo)
1266             .update(vk, device);
1267 
1268         const ShaderWrapper vertexModule(
1269             ShaderWrapper(vk, device, context.getBinaryCollection().get("sample_vert"), 0u));
1270         const ShaderWrapper fragmentModule(
1271             ShaderWrapper(vk, device, context.getBinaryCollection().get("sample_frag"), 0u));
1272         RenderPassWrapper renderPass(caseDef.pipelineConstructionType, vk, device, checksumFormat);
1273         renderPass.createFramebuffer(vk, device, 1u, &checksumImage.get(), &checksumImageView.get(),
1274                                      static_cast<uint32_t>(caseDef.renderSize.x()),
1275                                      static_cast<uint32_t>(caseDef.renderSize.y()));
1276         const PipelineLayoutWrapper pipelineLayout(caseDef.pipelineConstructionType, vk, device, *descriptorSetLayout);
1277 
1278         const bool isMonolithic(caseDef.pipelineConstructionType == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC);
1279         std::vector<PipelineSp> pipelinesSp;
1280         std::vector<GraphicsPipelineWrapper> pipelineWrapper;
1281 
1282         if (isMonolithic)
1283         {
1284             pipelinesSp =
1285                 makeGraphicsPipelines(vk, device, 1u, *pipelineLayout, *renderPass, vertexModule, fragmentModule,
1286                                       caseDef.renderSize, VK_SAMPLE_COUNT_1_BIT, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
1287         }
1288         else
1289         {
1290             pipelineWrapper.emplace_back(vki, vk, physicalDevice, device, context.getDeviceExtensions(),
1291                                          caseDef.pipelineConstructionType);
1292             preparePipelineWrapper(pipelineWrapper.back(), 0u, pipelineLayout, *renderPass, vertexModule,
1293                                    fragmentModule, caseDef.renderSize, VK_SAMPLE_COUNT_1_BIT,
1294                                    VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
1295         }
1296 
1297         beginCommandBuffer(vk, *cmdBuffer);
1298 
1299         // Prepare for sampling in the fragment shader
1300         {
1301             const VkImageMemoryBarrier barriers[] = {
1302                 {
1303                     VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,          // VkStructureType sType;
1304                     DE_NULL,                                         // const void* pNext;
1305                     VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,            // VkAccessFlags outputMask;
1306                     VK_ACCESS_SHADER_READ_BIT,                       // VkAccessFlags inputMask;
1307                     VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,        // VkImageLayout oldLayout;
1308                     VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,        // VkImageLayout newLayout;
1309                     VK_QUEUE_FAMILY_IGNORED,                         // uint32_t srcQueueFamilyIndex;
1310                     VK_QUEUE_FAMILY_IGNORED,                         // uint32_t destQueueFamilyIndex;
1311                     *colorImage,                                     // VkImage image;
1312                     makeColorSubresourceRange(0, caseDef.numLayers), // VkImageSubresourceRange subresourceRange;
1313                 },
1314             };
1315 
1316             vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
1317                                   VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL,
1318                                   DE_LENGTH_OF_ARRAY(barriers), barriers);
1319         }
1320 
1321         renderPass.begin(vk, *cmdBuffer, makeRect2D(0, 0, caseDef.renderSize.x(), caseDef.renderSize.y()),
1322                          tcu::UVec4(0u));
1323 
1324         if (isMonolithic)
1325             vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, **pipelinesSp.back());
1326         else
1327             pipelineWrapper.back().bind(*cmdBuffer);
1328         vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u,
1329                                  &descriptorSet.get(), 0u, DE_NULL);
1330         {
1331             const VkDeviceSize vertexBufferOffset = 0ull;
1332             vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
1333         }
1334 
1335         vk.cmdDraw(*cmdBuffer, static_cast<uint32_t>(vertices.size()), 1u, 0u, 0u);
1336         renderPass.end(vk, *cmdBuffer);
1337 
1338         copyImageToBuffer(vk, *cmdBuffer, *checksumImage, *checksumBuffer, caseDef.renderSize);
1339 
1340         endCommandBuffer(vk, *cmdBuffer);
1341         submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1342 
1343         // Verify result
1344 
1345         {
1346             invalidateAlloc(vk, device, *checksumBufferAlloc);
1347 
1348             const tcu::ConstPixelBufferAccess access(mapVkFormat(checksumFormat), caseDef.renderSize.x(),
1349                                                      caseDef.renderSize.y(), 1, checksumBufferAlloc->getHostPtr());
1350             const uint32_t numExpectedChecksum = getNumSamples(caseDef.numSamples) * caseDef.numLayers;
1351             bool multipleColorsPerTexelFound   = false;
1352 
1353             for (int y = 0; y < caseDef.renderSize.y(); ++y)
1354                 for (int x = 0; x < caseDef.renderSize.x(); ++x)
1355                 {
1356                     uint32_t clearColorCount     = access.getPixelUint(x, y).x();
1357                     uint32_t primitiveColorCount = access.getPixelUint(x, y).y();
1358 
1359                     if ((clearColorCount + primitiveColorCount) != numExpectedChecksum)
1360                         return tcu::TestStatus::fail("Some samples have incorrect color");
1361 
1362                     if ((clearColorCount > 0) && (primitiveColorCount > 0))
1363                         multipleColorsPerTexelFound = true;
1364                 }
1365 
1366             // For a multisampled image, we are expecting some texels to have samples of both clear color and primitive color
1367             if (!multipleColorsPerTexelFound)
1368                 return tcu::TestStatus::fail(
1369                     "Could not find texels with samples of both clear color and primitive color");
1370         }
1371     }
1372 
1373     return tcu::TestStatus::pass("OK");
1374 }
1375 
1376 } // namespace SampledImage
1377 
1378 namespace StorageImage
1379 {
1380 
initPrograms(SourceCollections & programCollection,const CaseDef caseDef)1381 void initPrograms(SourceCollections &programCollection, const CaseDef caseDef)
1382 {
1383     // Vertex & fragment
1384 
1385     addSimpleVertexAndFragmentPrograms(programCollection, caseDef);
1386 
1387     // Compute
1388     {
1389         const std::string imageTypeStr =
1390             getShaderMultisampledImageType(mapVkFormat(caseDef.colorFormat), caseDef.numLayers);
1391         const std::string formatQualifierStr = getShaderImageFormatQualifier(mapVkFormat(caseDef.colorFormat));
1392         const std::string signednessPrefix   = isUintFormat(caseDef.colorFormat) ? "u" :
1393                                                isIntFormat(caseDef.colorFormat)  ? "i" :
1394                                                                                    "";
1395         const std::string gvec4Expr          = signednessPrefix + "vec4";
1396         const std::string texelCoordStr      = (caseDef.numLayers == 1 ? "ivec2(gx, gy)" : "ivec3(gx, gy, gz)");
1397 
1398         std::ostringstream src;
1399         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1400             << "layout(local_size_x = 1) in;\n"
1401             << "layout(set = 0, binding = 0, " << formatQualifierStr << ") uniform " << imageTypeStr << " u_msImage;\n"
1402             << "\n"
1403             << "void main(void)\n"
1404             << "{\n"
1405             << "    int gx = int(gl_GlobalInvocationID.x);\n"
1406             << "    int gy = int(gl_GlobalInvocationID.y);\n"
1407             << "    int gz = int(gl_GlobalInvocationID.z);\n"
1408             << "\n"
1409             << "    " << gvec4Expr << " prevColor = imageLoad(u_msImage, " << texelCoordStr << ", 0);\n"
1410             << "    for (int sampleNdx = 1; sampleNdx < " << caseDef.numSamples << "; ++sampleNdx) {\n"
1411             << "        " << gvec4Expr << " color = imageLoad(u_msImage, " << texelCoordStr << ", sampleNdx);\n"
1412             << "        imageStore(u_msImage, " << texelCoordStr << ", sampleNdx, prevColor);\n"
1413             << "        prevColor = color;\n"
1414             << "    }\n"
1415             << "    imageStore(u_msImage, " << texelCoordStr << ", 0, prevColor);\n"
1416             << "}\n";
1417 
1418         programCollection.glslSources.add("comp") << glu::ComputeSource(src.str());
1419     }
1420 }
1421 
1422 //! Render a MS image, resolve it, and copy result to resolveBuffer.
renderAndResolve(Context & context,const CaseDef & caseDef,const VkBuffer resolveBuffer,const bool useComputePass)1423 void renderAndResolve(Context &context, const CaseDef &caseDef, const VkBuffer resolveBuffer, const bool useComputePass)
1424 {
1425     const DeviceInterface &vk       = context.getDeviceInterface();
1426     const VkDevice device           = context.getDevice();
1427     const VkQueue queue             = context.getUniversalQueue();
1428     const uint32_t queueFamilyIndex = context.getUniversalQueueFamilyIndex();
1429     Allocator &allocator            = context.getDefaultAllocator();
1430 
1431     // Multisampled color image
1432     const Unique<VkImage> colorImage(makeImage(vk, device, caseDef.colorFormat, caseDef.renderSize, caseDef.numLayers,
1433                                                caseDef.numSamples,
1434                                                VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT |
1435                                                    VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT));
1436     const UniquePtr<Allocation> colorImageAlloc(bindImage(vk, device, allocator, *colorImage, MemoryRequirement::Any));
1437 
1438     const Unique<VkImage> resolveImage(makeImage(vk, device, caseDef.colorFormat, caseDef.renderSize, caseDef.numLayers,
1439                                                  VK_SAMPLE_COUNT_1_BIT,
1440                                                  VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT));
1441     const UniquePtr<Allocation> resolveImageAlloc(
1442         bindImage(vk, device, allocator, *resolveImage, MemoryRequirement::Any));
1443 
1444     const Unique<VkCommandPool> cmdPool(
1445         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1446     const Unique<VkCommandBuffer> cmdBuffer(makeCommandBuffer(vk, device, *cmdPool));
1447 
1448     // Working image barrier, we change it based on which rendering stages were executed so far.
1449     VkImageMemoryBarrier colorImageBarrier = {
1450         VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,          // VkStructureType sType;
1451         DE_NULL,                                         // const void* pNext;
1452         (VkAccessFlags)0,                                // VkAccessFlags outputMask;
1453         (VkAccessFlags)0,                                // VkAccessFlags inputMask;
1454         VK_IMAGE_LAYOUT_UNDEFINED,                       // VkImageLayout oldLayout;
1455         VK_IMAGE_LAYOUT_UNDEFINED,                       // VkImageLayout newLayout;
1456         VK_QUEUE_FAMILY_IGNORED,                         // uint32_t srcQueueFamilyIndex;
1457         VK_QUEUE_FAMILY_IGNORED,                         // uint32_t destQueueFamilyIndex;
1458         *colorImage,                                     // VkImage image;
1459         makeColorSubresourceRange(0, caseDef.numLayers), // VkImageSubresourceRange subresourceRange;
1460     };
1461 
1462     // Pass 1: Render an image
1463     {
1464         renderMultisampledImage(context, caseDef, *colorImage);
1465 
1466         colorImageBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
1467         colorImageBarrier.oldLayout     = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1468     }
1469 
1470     // Pass 2: Compute shader
1471     if (useComputePass)
1472     {
1473         // Descriptors
1474 
1475         Unique<VkDescriptorSetLayout> descriptorSetLayout(
1476             DescriptorSetLayoutBuilder()
1477                 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
1478                 .build(vk, device));
1479 
1480         Unique<VkDescriptorPool> descriptorPool(
1481             DescriptorPoolBuilder()
1482                 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1u)
1483                 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
1484 
1485         const Unique<VkImageView> colorImageView(makeImageView(
1486             vk, device, *colorImage, (caseDef.numLayers == 1 ? VK_IMAGE_VIEW_TYPE_2D : VK_IMAGE_VIEW_TYPE_2D_ARRAY),
1487             caseDef.colorFormat, makeColorSubresourceRange(0, caseDef.numLayers)));
1488         const Unique<VkDescriptorSet> descriptorSet(
1489             makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
1490         const VkDescriptorImageInfo descriptorImageInfo =
1491             makeDescriptorImageInfo(DE_NULL, *colorImageView, VK_IMAGE_LAYOUT_GENERAL);
1492 
1493         DescriptorSetUpdateBuilder()
1494             .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
1495                          VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorImageInfo)
1496             .update(vk, device);
1497 
1498         const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(vk, device, *descriptorSetLayout));
1499         const Unique<VkShaderModule> shaderModule(
1500             createShaderModule(vk, device, context.getBinaryCollection().get("comp"), 0));
1501         const Unique<VkPipeline> pipeline(makeComputePipeline(vk, device, *pipelineLayout, *shaderModule));
1502 
1503         beginCommandBuffer(vk, *cmdBuffer);
1504 
1505         // Image layout for load/stores
1506         {
1507             colorImageBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
1508             colorImageBarrier.newLayout     = VK_IMAGE_LAYOUT_GENERAL;
1509 
1510             vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
1511                                   VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u,
1512                                   &colorImageBarrier);
1513 
1514             colorImageBarrier.srcAccessMask = colorImageBarrier.dstAccessMask;
1515             colorImageBarrier.oldLayout     = colorImageBarrier.newLayout;
1516         }
1517         // Dispatch
1518         {
1519             vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
1520             vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u,
1521                                      &descriptorSet.get(), 0u, DE_NULL);
1522             vk.cmdDispatch(*cmdBuffer, caseDef.renderSize.x(), caseDef.renderSize.y(), caseDef.numLayers);
1523         }
1524 
1525         endCommandBuffer(vk, *cmdBuffer);
1526         submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1527     }
1528 
1529     // Resolve and verify the image
1530     {
1531         beginCommandBuffer(vk, *cmdBuffer);
1532 
1533         // Prepare for resolve
1534         {
1535             colorImageBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
1536             colorImageBarrier.newLayout     = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
1537 
1538             const VkImageMemoryBarrier barriers[] = {
1539                 colorImageBarrier,
1540                 {
1541                     VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,          // VkStructureType sType;
1542                     DE_NULL,                                         // const void* pNext;
1543                     (VkAccessFlags)0,                                // VkAccessFlags outputMask;
1544                     VK_ACCESS_TRANSFER_WRITE_BIT,                    // VkAccessFlags inputMask;
1545                     VK_IMAGE_LAYOUT_UNDEFINED,                       // VkImageLayout oldLayout;
1546                     VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,            // VkImageLayout newLayout;
1547                     VK_QUEUE_FAMILY_IGNORED,                         // uint32_t srcQueueFamilyIndex;
1548                     VK_QUEUE_FAMILY_IGNORED,                         // uint32_t destQueueFamilyIndex;
1549                     *resolveImage,                                   // VkImage image;
1550                     makeColorSubresourceRange(0, caseDef.numLayers), // VkImageSubresourceRange subresourceRange;
1551                 },
1552             };
1553 
1554             const VkPipelineStageFlags srcStageMask =
1555                 (colorImageBarrier.srcAccessMask == VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT) ?
1556                     VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT :
1557                     VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
1558 
1559             vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u,
1560                                   DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers);
1561 
1562             colorImageBarrier.srcAccessMask = colorImageBarrier.dstAccessMask;
1563             colorImageBarrier.oldLayout     = colorImageBarrier.newLayout;
1564         }
1565         // Resolve the image
1566         {
1567             const VkImageResolve resolveRegion = {
1568                 makeColorSubresourceLayers(0, caseDef.numLayers), // VkImageSubresourceLayers    srcSubresource;
1569                 makeOffset3D(0, 0, 0),                            // VkOffset3D                  srcOffset;
1570                 makeColorSubresourceLayers(0, caseDef.numLayers), // VkImageSubresourceLayers    dstSubresource;
1571                 makeOffset3D(0, 0, 0),                            // VkOffset3D                  dstOffset;
1572                 makeExtent3D(caseDef.renderSize.x(), caseDef.renderSize.y(), 1u), // VkExtent3D                  extent;
1573             };
1574 
1575             vk.cmdResolveImage(*cmdBuffer, *colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *resolveImage,
1576                                VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, &resolveRegion);
1577         }
1578 
1579         copyImageToBuffer(vk, *cmdBuffer, *resolveImage, resolveBuffer, caseDef.renderSize,
1580                           VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, caseDef.numLayers);
1581 
1582         endCommandBuffer(vk, *cmdBuffer);
1583         submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1584     }
1585 }
1586 
1587 //! Exact image compare, but allow for some error when color format is integer.
compareImages(tcu::TestLog & log,const CaseDef & caseDef,const tcu::ConstPixelBufferAccess layeredReferenceImage,const tcu::ConstPixelBufferAccess layeredActualImage)1588 bool compareImages(tcu::TestLog &log, const CaseDef &caseDef, const tcu::ConstPixelBufferAccess layeredReferenceImage,
1589                    const tcu::ConstPixelBufferAccess layeredActualImage)
1590 {
1591     DE_ASSERT(caseDef.numSamples > 1);
1592 
1593     const Vec4 goodColor      = Vec4(0.0f, 1.0f, 0.0f, 1.0f);
1594     const Vec4 badColor       = Vec4(1.0f, 0.0f, 0.0f, 1.0f);
1595     const bool isAnyIntFormat = isIntFormat(caseDef.colorFormat) || isUintFormat(caseDef.colorFormat);
1596 
1597     // There should be no mismatched pixels for non-integer formats. Otherwise we may get a wrong color in a location where sample coverage isn't exactly 0 or 1.
1598     const int badPixelTolerance = (isAnyIntFormat ? 2 * caseDef.renderSize.x() : 0);
1599     int goodLayers              = 0;
1600 
1601     for (int layerNdx = 0; layerNdx < caseDef.numLayers; ++layerNdx)
1602     {
1603         const tcu::ConstPixelBufferAccess referenceImage =
1604             tcu::getSubregion(layeredReferenceImage, 0, 0, layerNdx, caseDef.renderSize.x(), caseDef.renderSize.y(), 1);
1605         const tcu::ConstPixelBufferAccess actualImage =
1606             tcu::getSubregion(layeredActualImage, 0, 0, layerNdx, caseDef.renderSize.x(), caseDef.renderSize.y(), 1);
1607         const std::string imageName = "color layer " + de::toString(layerNdx);
1608 
1609         tcu::TextureLevel errorMaskStorage(tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8),
1610                                            caseDef.renderSize.x(), caseDef.renderSize.y());
1611         tcu::PixelBufferAccess errorMask = errorMaskStorage.getAccess();
1612         int numBadPixels                 = 0;
1613 
1614         for (int y = 0; y < caseDef.renderSize.y(); ++y)
1615             for (int x = 0; x < caseDef.renderSize.x(); ++x)
1616             {
1617                 if (isAnyIntFormat && (referenceImage.getPixelInt(x, y) == actualImage.getPixelInt(x, y)))
1618                     errorMask.setPixel(goodColor, x, y);
1619                 else if (referenceImage.getPixel(x, y) == actualImage.getPixel(x, y))
1620                     errorMask.setPixel(goodColor, x, y);
1621                 else
1622                 {
1623                     ++numBadPixels;
1624                     errorMask.setPixel(badColor, x, y);
1625                 }
1626             }
1627 
1628         if (numBadPixels <= badPixelTolerance)
1629         {
1630             ++goodLayers;
1631 
1632             log << tcu::TestLog::ImageSet(imageName, imageName) << tcu::TestLog::Image("Result", "Result", actualImage)
1633                 << tcu::TestLog::EndImageSet;
1634         }
1635         else
1636         {
1637             log << tcu::TestLog::ImageSet(imageName, imageName) << tcu::TestLog::Image("Result", "Result", actualImage)
1638                 << tcu::TestLog::Image("Reference", "Reference", referenceImage)
1639                 << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask) << tcu::TestLog::EndImageSet;
1640         }
1641     }
1642 
1643     if (goodLayers == caseDef.numLayers)
1644     {
1645         log << tcu::TestLog::Message << "All rendered images are correct." << tcu::TestLog::EndMessage;
1646         return true;
1647     }
1648     else
1649     {
1650         log << tcu::TestLog::Message << "FAILED: Some rendered images were incorrect." << tcu::TestLog::EndMessage;
1651         return false;
1652     }
1653 }
1654 
checkSupport(Context & context,const CaseDef caseDef)1655 void checkSupport(Context &context, const CaseDef caseDef)
1656 {
1657     const VkImageUsageFlags colorImageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT;
1658 
1659     checkImageFormatRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), caseDef.numSamples,
1660                                  caseDef.colorFormat, colorImageUsage);
1661     checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
1662                                           caseDef.pipelineConstructionType);
1663 }
1664 
test(Context & context,const CaseDef caseDef)1665 tcu::TestStatus test(Context &context, const CaseDef caseDef)
1666 {
1667     const DeviceInterface &vk = context.getDeviceInterface();
1668     const VkDevice device     = context.getDevice();
1669     Allocator &allocator      = context.getDefaultAllocator();
1670 
1671     {
1672         tcu::TestLog &log = context.getTestContext().getLog();
1673         log << tcu::LogSection("Description", "") << tcu::TestLog::Message
1674             << "Rendering to a multisampled image. Image will be processed with a compute shader using OpImageRead and "
1675                "OpImageWrite."
1676             << tcu::TestLog::EndMessage << tcu::TestLog::Message
1677             << "Expecting the processed image to be roughly the same as the input image (deviation may occur for "
1678                "integer formats)."
1679             << tcu::TestLog::EndMessage << tcu::TestLog::EndSection;
1680     }
1681 
1682     // Host-readable buffer
1683     const VkDeviceSize resolveBufferSize = caseDef.renderSize.x() * caseDef.renderSize.y() * caseDef.numLayers *
1684                                            tcu::getPixelSize(mapVkFormat(caseDef.colorFormat));
1685     const Unique<VkBuffer> resolveImageOneBuffer(
1686         makeBuffer(vk, device, resolveBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
1687     const UniquePtr<Allocation> resolveImageOneBufferAlloc(
1688         bindBuffer(vk, device, allocator, *resolveImageOneBuffer, MemoryRequirement::HostVisible));
1689     const Unique<VkBuffer> resolveImageTwoBuffer(
1690         makeBuffer(vk, device, resolveBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
1691     const UniquePtr<Allocation> resolveImageTwoBufferAlloc(
1692         bindBuffer(vk, device, allocator, *resolveImageTwoBuffer, MemoryRequirement::HostVisible));
1693 
1694     zeroBuffer(vk, device, *resolveImageOneBufferAlloc, resolveBufferSize);
1695     zeroBuffer(vk, device, *resolveImageTwoBufferAlloc, resolveBufferSize);
1696 
1697     // Render: repeat the same rendering twice to avoid non-essential API calls and layout transitions (e.g. copy).
1698     {
1699         renderAndResolve(context, caseDef, *resolveImageOneBuffer, false); // Pass 1: render a basic multisampled image
1700         renderAndResolve(context, caseDef, *resolveImageTwoBuffer,
1701                          true); // Pass 2: the same but altered with a compute shader
1702     }
1703 
1704     // Verify
1705     {
1706         invalidateAlloc(vk, device, *resolveImageOneBufferAlloc);
1707         invalidateAlloc(vk, device, *resolveImageTwoBufferAlloc);
1708 
1709         const tcu::PixelBufferAccess layeredImageOne(mapVkFormat(caseDef.colorFormat), caseDef.renderSize.x(),
1710                                                      caseDef.renderSize.y(), caseDef.numLayers,
1711                                                      resolveImageOneBufferAlloc->getHostPtr());
1712         const tcu::ConstPixelBufferAccess layeredImageTwo(mapVkFormat(caseDef.colorFormat), caseDef.renderSize.x(),
1713                                                           caseDef.renderSize.y(), caseDef.numLayers,
1714                                                           resolveImageTwoBufferAlloc->getHostPtr());
1715 
1716         // Check all layers
1717         if (!compareImages(context.getTestContext().getLog(), caseDef, layeredImageOne, layeredImageTwo))
1718             return tcu::TestStatus::fail("Rendered images are not correct");
1719     }
1720 
1721     return tcu::TestStatus::pass("OK");
1722 }
1723 
1724 } // namespace StorageImage
1725 
1726 namespace StandardSamplePosition
1727 {
1728 
initPrograms(SourceCollections & programCollection,const CaseDef caseDef)1729 void initPrograms(SourceCollections &programCollection, const CaseDef caseDef)
1730 {
1731     // Pass 1: Render to texture
1732 
1733     addSimpleVertexAndFragmentPrograms(programCollection, caseDef);
1734 
1735     // Pass 2: Sample texture
1736 
1737     // Vertex shader
1738     {
1739         std::ostringstream src;
1740         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1741             << "\n"
1742             << "layout(location = 0) in  vec4  in_position;\n"
1743             << "\n"
1744             << "out gl_PerVertex {\n"
1745             << "    vec4 gl_Position;\n"
1746             << "};\n"
1747             << "\n"
1748             << "void main(void)\n"
1749             << "{\n"
1750             << "    gl_Position = in_position;\n"
1751             << "}\n";
1752 
1753         programCollection.glslSources.add("sample_vert") << glu::VertexSource(src.str());
1754     }
1755 
1756     // Fragment shader
1757     {
1758         std::ostringstream src;
1759         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1760             << "\n"
1761             << "layout(location = 0) out uint o_status;\n"
1762             << "\n"
1763             << "layout(set = 0, binding = 0) uniform sampler2DMS colorTexture;\n"
1764             << "\n"
1765             << "void main(void)\n"
1766             << "{\n"
1767             << "    uint result = 0;\n"
1768             << "    vec4 a, b;\n\n"
1769             << "\n";
1770 
1771         for (uint32_t sampleNdx = 0; sampleNdx < (uint32_t)caseDef.numSamples; sampleNdx++)
1772         {
1773             Vec4 expectedColor = sampleIndexToColor(sampleNdx);
1774 
1775             src << "    a = texelFetch(colorTexture, ivec2(0,0), " << sampleNdx
1776                 << ");\n"
1777                    "    b = vec4("
1778                 << expectedColor.x() << ", " << expectedColor.y() << ", " << expectedColor.z()
1779                 << ", 1.0);\n"
1780                    "    if (abs(a.x - b.x) > 0.1 || abs(a.y - b.y) > 0.1 || abs(a.z - b.z) > 0.1) result++;\n";
1781         }
1782 
1783         src << "\n"
1784             << "    o_status = result;\n"
1785             << "}\n";
1786 
1787         programCollection.glslSources.add("sample_frag") << glu::FragmentSource(src.str());
1788     }
1789 }
1790 
checkSupport(Context & context,const CaseDef caseDef)1791 void checkSupport(Context &context, const CaseDef caseDef)
1792 {
1793     const VkImageUsageFlags colorImageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
1794     const VkPhysicalDeviceProperties props =
1795         getPhysicalDeviceProperties(context.getInstanceInterface(), context.getPhysicalDevice());
1796 
1797     checkImageFormatRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), caseDef.numSamples,
1798                                  caseDef.colorFormat, colorImageUsage);
1799 
1800     if (!props.limits.standardSampleLocations)
1801         TCU_THROW(NotSupportedError, "Device does not support standard sample locations.");
1802 
1803     if (caseDef.numSamples == VK_SAMPLE_COUNT_32_BIT || caseDef.numSamples == VK_SAMPLE_COUNT_64_BIT)
1804     {
1805         TCU_THROW(InternalError, "Standard does not define sample positions for 32x or 64x multisample modes");
1806     }
1807 
1808     checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
1809                                           caseDef.pipelineConstructionType);
1810 }
1811 
test(Context & context,const CaseDef caseDef)1812 tcu::TestStatus test(Context &context, const CaseDef caseDef)
1813 {
1814     const InstanceInterface &vki          = context.getInstanceInterface();
1815     const DeviceInterface &vk             = context.getDeviceInterface();
1816     const VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
1817     const VkDevice device                 = context.getDevice();
1818     const VkQueue queue                   = context.getUniversalQueue();
1819     const uint32_t queueFamilyIndex       = context.getUniversalQueueFamilyIndex();
1820     Allocator &allocator                  = context.getDefaultAllocator();
1821 
1822     const VkImageUsageFlags colorImageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
1823 
1824     {
1825         tcu::TestLog &log = context.getTestContext().getLog();
1826         log << tcu::LogSection("Description", "") << tcu::TestLog::Message
1827             << "Rendering to a multisampled image. Expecting samples to have specified colors."
1828             << tcu::TestLog::EndMessage << tcu::TestLog::Message
1829             << "Sampling from the texture with texelFetch (OpImageFetch)." << tcu::TestLog::EndMessage
1830             << tcu::TestLog::EndSection;
1831     }
1832 
1833     // Multisampled color image
1834     const Unique<VkImage> colorImage(makeImage(vk, device, caseDef.colorFormat, caseDef.renderSize, caseDef.numLayers,
1835                                                caseDef.numSamples, colorImageUsage));
1836     const UniquePtr<Allocation> colorImageAlloc(bindImage(vk, device, allocator, *colorImage, MemoryRequirement::Any));
1837 
1838     const Unique<VkCommandPool> cmdPool(
1839         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1840     const Unique<VkCommandBuffer> cmdBuffer(makeCommandBuffer(vk, device, *cmdPool));
1841 
1842     // Step 1: Render to texture
1843     {
1844         renderMultisampledImage(context, caseDef, *colorImage);
1845     }
1846 
1847     // Step 2: Sample texture
1848     {
1849         // Color image view
1850         const VkImageViewType colorImageViewType =
1851             (caseDef.numLayers == 1 ? VK_IMAGE_VIEW_TYPE_2D : VK_IMAGE_VIEW_TYPE_2D_ARRAY);
1852         const Unique<VkImageView> colorImageView(makeImageView(vk, device, *colorImage, colorImageViewType,
1853                                                                caseDef.colorFormat,
1854                                                                makeColorSubresourceRange(0, caseDef.numLayers)));
1855         const Unique<VkSampler> colorSampler(makeSampler(vk, device));
1856 
1857         // Checksum image
1858         const VkFormat checksumFormat = VK_FORMAT_R8_UINT;
1859         const Unique<VkImage> checksumImage(
1860             makeImage(vk, device, checksumFormat, caseDef.renderSize, 1u, VK_SAMPLE_COUNT_1_BIT,
1861                       VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT));
1862         const UniquePtr<Allocation> checksumImageAlloc(
1863             bindImage(vk, device, allocator, *checksumImage, MemoryRequirement::Any));
1864         const Unique<VkImageView> checksumImageView(makeImageView(vk, device, *checksumImage, VK_IMAGE_VIEW_TYPE_2D,
1865                                                                   checksumFormat, makeColorSubresourceRange(0, 1)));
1866 
1867         // Checksum buffer (for host reading)
1868         const VkDeviceSize checksumBufferSize =
1869             caseDef.renderSize.x() * caseDef.renderSize.y() * tcu::getPixelSize(mapVkFormat(checksumFormat));
1870         const Unique<VkBuffer> checksumBuffer(
1871             makeBuffer(vk, device, checksumBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
1872         const UniquePtr<Allocation> checksumBufferAlloc(
1873             bindBuffer(vk, device, allocator, *checksumBuffer, MemoryRequirement::HostVisible));
1874 
1875         zeroBuffer(vk, device, *checksumBufferAlloc, checksumBufferSize);
1876 
1877         // Vertex buffer
1878         const std::vector<Vertex4RGBA> vertices = genFullQuadVertices();
1879         const VkDeviceSize vertexBufferSize     = sizeInBytes(vertices);
1880         const Unique<VkBuffer> vertexBuffer(
1881             makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
1882         const UniquePtr<Allocation> vertexBufferAlloc(
1883             bindBuffer(vk, device, allocator, *vertexBuffer, MemoryRequirement::HostVisible));
1884 
1885         {
1886             deMemcpy(vertexBufferAlloc->getHostPtr(), &vertices[0], static_cast<std::size_t>(vertexBufferSize));
1887             flushAlloc(vk, device, *vertexBufferAlloc);
1888         }
1889 
1890         // Descriptors
1891         // \note OpImageFetch doesn't use a sampler, but in GLSL texelFetch needs a sampler2D which translates to a combined image sampler in Vulkan.
1892 
1893         const Unique<VkDescriptorSetLayout> descriptorSetLayout(
1894             DescriptorSetLayoutBuilder()
1895                 .addSingleSamplerBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT,
1896                                          &colorSampler.get())
1897                 .build(vk, device));
1898 
1899         const Unique<VkDescriptorPool> descriptorPool(
1900             DescriptorPoolBuilder()
1901                 .addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
1902                 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
1903 
1904         const Unique<VkDescriptorSet> descriptorSet(
1905             makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
1906         const VkDescriptorImageInfo imageDescriptorInfo =
1907             makeDescriptorImageInfo(DE_NULL, *colorImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
1908 
1909         DescriptorSetUpdateBuilder()
1910             .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
1911                          VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageDescriptorInfo)
1912             .update(vk, device);
1913 
1914         const ShaderWrapper vertexModule(
1915             ShaderWrapper(vk, device, context.getBinaryCollection().get("sample_vert"), 0u));
1916         const ShaderWrapper fragmentModule(
1917             ShaderWrapper(vk, device, context.getBinaryCollection().get("sample_frag"), 0u));
1918         RenderPassWrapper renderPass(
1919             makeSimpleRenderPass(vk, device, caseDef.pipelineConstructionType, checksumFormat));
1920         renderPass.createFramebuffer(vk, device, 1u, &checksumImage.get(), &checksumImageView.get(),
1921                                      static_cast<uint32_t>(caseDef.renderSize.x()),
1922                                      static_cast<uint32_t>(caseDef.renderSize.y()));
1923         const PipelineLayoutWrapper pipelineLayout(caseDef.pipelineConstructionType, vk, device, *descriptorSetLayout);
1924         const bool isMonolithic(caseDef.pipelineConstructionType == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC);
1925         std::vector<PipelineSp> pipelinesSp;
1926         std::vector<GraphicsPipelineWrapper> pipelineWrapper;
1927 
1928         if (isMonolithic)
1929         {
1930             pipelinesSp =
1931                 makeGraphicsPipelines(vk, device, 1u, *pipelineLayout, *renderPass, vertexModule, fragmentModule,
1932                                       caseDef.renderSize, VK_SAMPLE_COUNT_1_BIT, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
1933         }
1934         else
1935         {
1936             pipelineWrapper.emplace_back(vki, vk, physicalDevice, device, context.getDeviceExtensions(),
1937                                          caseDef.pipelineConstructionType);
1938             preparePipelineWrapper(pipelineWrapper.back(), 0u, pipelineLayout, *renderPass, vertexModule,
1939                                    fragmentModule, caseDef.renderSize, VK_SAMPLE_COUNT_1_BIT,
1940                                    VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
1941         }
1942 
1943         beginCommandBuffer(vk, *cmdBuffer);
1944 
1945         // Prepare for sampling in the fragment shader
1946         {
1947             const VkImageMemoryBarrier barriers[] = {
1948                 {
1949                     VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,          // VkStructureType sType;
1950                     DE_NULL,                                         // const void* pNext;
1951                     VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,            // VkAccessFlags outputMask;
1952                     VK_ACCESS_SHADER_READ_BIT,                       // VkAccessFlags inputMask;
1953                     VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,        // VkImageLayout oldLayout;
1954                     VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,        // VkImageLayout newLayout;
1955                     VK_QUEUE_FAMILY_IGNORED,                         // uint32_t srcQueueFamilyIndex;
1956                     VK_QUEUE_FAMILY_IGNORED,                         // uint32_t destQueueFamilyIndex;
1957                     *colorImage,                                     // VkImage image;
1958                     makeColorSubresourceRange(0, caseDef.numLayers), // VkImageSubresourceRange subresourceRange;
1959                 },
1960             };
1961 
1962             vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
1963                                   VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL,
1964                                   DE_LENGTH_OF_ARRAY(barriers), barriers);
1965         }
1966 
1967         renderPass.begin(vk, *cmdBuffer, makeRect2D(0, 0, caseDef.renderSize.x(), caseDef.renderSize.y()),
1968                          tcu::UVec4(0u));
1969 
1970         if (isMonolithic)
1971             vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, **pipelinesSp.back());
1972         else
1973             pipelineWrapper.back().bind(*cmdBuffer);
1974         vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u,
1975                                  &descriptorSet.get(), 0u, DE_NULL);
1976         {
1977             const VkDeviceSize vertexBufferOffset = 0ull;
1978             vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
1979         }
1980 
1981         vk.cmdDraw(*cmdBuffer, static_cast<uint32_t>(vertices.size()), 1u, 0u, 0u);
1982         renderPass.end(vk, *cmdBuffer);
1983 
1984         copyImageToBuffer(vk, *cmdBuffer, *checksumImage, *checksumBuffer, caseDef.renderSize);
1985 
1986         endCommandBuffer(vk, *cmdBuffer);
1987         submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1988 
1989         // Verify result
1990 
1991         {
1992             invalidateAlloc(vk, device, *checksumBufferAlloc);
1993 
1994             const tcu::ConstPixelBufferAccess access(mapVkFormat(checksumFormat), caseDef.renderSize.x(),
1995                                                      caseDef.renderSize.y(), 1, checksumBufferAlloc->getHostPtr());
1996 
1997             uint32_t result = access.getPixelUint(0, 0).x();
1998 
1999             if (result)
2000                 return tcu::TestStatus::fail(std::to_string(result) + " multisamples have unexpected color.");
2001         }
2002     }
2003 
2004     return tcu::TestStatus::pass("OK");
2005 }
2006 
2007 } // namespace StandardSamplePosition
2008 
getSizeLayerString(const IVec2 & size,const int numLayers)2009 std::string getSizeLayerString(const IVec2 &size, const int numLayers)
2010 {
2011     std::ostringstream str;
2012     str << size.x() << "x" << size.y() << "_" << numLayers;
2013     return str.str();
2014 }
2015 
getFormatString(const VkFormat format)2016 std::string getFormatString(const VkFormat format)
2017 {
2018     std::string name(getFormatName(format));
2019     return de::toLower(name.substr(10));
2020 }
2021 
addTestCasesWithFunctions(tcu::TestCaseGroup * group,FunctionSupport1<CaseDef>::Function checkSupport,FunctionPrograms1<CaseDef>::Function initPrograms,FunctionInstance1<CaseDef>::Function testFunc,PipelineConstructionType pipelineConstructionType)2022 void addTestCasesWithFunctions(tcu::TestCaseGroup *group, FunctionSupport1<CaseDef>::Function checkSupport,
2023                                FunctionPrograms1<CaseDef>::Function initPrograms,
2024                                FunctionInstance1<CaseDef>::Function testFunc,
2025                                PipelineConstructionType pipelineConstructionType)
2026 {
2027     const IVec2 size[] = {
2028         IVec2(64, 64),
2029         IVec2(79, 31),
2030     };
2031     const int numLayers[]                 = {1, 4};
2032     const VkSampleCountFlagBits samples[] = {
2033         VK_SAMPLE_COUNT_2_BIT,  VK_SAMPLE_COUNT_4_BIT,  VK_SAMPLE_COUNT_8_BIT,
2034         VK_SAMPLE_COUNT_16_BIT, VK_SAMPLE_COUNT_32_BIT, VK_SAMPLE_COUNT_64_BIT,
2035     };
2036     const VkFormat format[] = {
2037         VK_FORMAT_R8G8B8A8_UNORM,
2038         VK_FORMAT_R32_UINT,
2039         VK_FORMAT_R16G16_SINT,
2040         VK_FORMAT_R32G32B32A32_SFLOAT,
2041     };
2042 
2043     for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(size); ++sizeNdx)
2044         for (int layerNdx = 0; layerNdx < DE_LENGTH_OF_ARRAY(numLayers); ++layerNdx)
2045         {
2046             MovePtr<tcu::TestCaseGroup> sizeLayerGroup(new tcu::TestCaseGroup(
2047                 group->getTestContext(), getSizeLayerString(size[sizeNdx], numLayers[layerNdx]).c_str()));
2048             for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(format); ++formatNdx)
2049             {
2050                 MovePtr<tcu::TestCaseGroup> formatGroup(
2051                     new tcu::TestCaseGroup(group->getTestContext(), getFormatString(format[formatNdx]).c_str()));
2052                 for (int samplesNdx = 0; samplesNdx < DE_LENGTH_OF_ARRAY(samples); ++samplesNdx)
2053                 {
2054                     std::ostringstream caseName;
2055                     caseName << "samples_" << getNumSamples(samples[samplesNdx]);
2056 
2057                     const CaseDef caseDef{
2058                         pipelineConstructionType, // PipelineConstructionType pipelineConstructionType;
2059                         size[sizeNdx],            // IVec2 renderSize;
2060                         numLayers[layerNdx],      // int numLayers;
2061                         format[formatNdx],        // VkFormat colorFormat;
2062                         samples[samplesNdx],      // VkSampleCountFlagBits numSamples;
2063                         false,                    // bool colorQuad;
2064                     };
2065 
2066                     addFunctionCaseWithPrograms(formatGroup.get(), caseName.str(), checkSupport, initPrograms, testFunc,
2067                                                 caseDef);
2068                 }
2069                 sizeLayerGroup->addChild(formatGroup.release());
2070             }
2071             group->addChild(sizeLayerGroup.release());
2072         }
2073 }
2074 
addStandardSamplePositionTestCasesWithFunctions(tcu::TestCaseGroup * group,FunctionSupport1<CaseDef>::Function checkSupport,FunctionPrograms1<CaseDef>::Function initPrograms,FunctionInstance1<CaseDef>::Function testFunc,PipelineConstructionType pipelineConstructionType)2075 void addStandardSamplePositionTestCasesWithFunctions(tcu::TestCaseGroup *group,
2076                                                      FunctionSupport1<CaseDef>::Function checkSupport,
2077                                                      FunctionPrograms1<CaseDef>::Function initPrograms,
2078                                                      FunctionInstance1<CaseDef>::Function testFunc,
2079                                                      PipelineConstructionType pipelineConstructionType)
2080 {
2081     const VkSampleCountFlagBits samples[] = {
2082         VK_SAMPLE_COUNT_2_BIT,  VK_SAMPLE_COUNT_4_BIT,  VK_SAMPLE_COUNT_8_BIT,
2083         VK_SAMPLE_COUNT_16_BIT, VK_SAMPLE_COUNT_32_BIT, VK_SAMPLE_COUNT_64_BIT,
2084     };
2085     const VkFormat format[] = {
2086         VK_FORMAT_R8G8B8A8_UNORM,
2087         VK_FORMAT_R32G32B32A32_SFLOAT,
2088     };
2089 
2090     for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(format); ++formatNdx)
2091     {
2092         MovePtr<tcu::TestCaseGroup> formatGroup(
2093             new tcu::TestCaseGroup(group->getTestContext(), getFormatString(format[formatNdx]).c_str()));
2094         for (int samplesNdx = 0; samplesNdx < DE_LENGTH_OF_ARRAY(samples); ++samplesNdx)
2095         {
2096             std::ostringstream caseName;
2097             caseName << "samples_" << getNumSamples(samples[samplesNdx]);
2098 
2099             const CaseDef caseDef{
2100                 pipelineConstructionType, // PipelineConstructionType pipelineConstructionType;
2101                 IVec2(1, 1),              // IVec2 renderSize;
2102                 1,                        // int numLayers;
2103                 format[formatNdx],        // VkFormat colorFormat;
2104                 samples[samplesNdx],      // VkSampleCountFlagBits numSamples;
2105                 true,                     // bool colorQuad;
2106             };
2107 
2108             addFunctionCaseWithPrograms(formatGroup.get(), caseName.str(), checkSupport, initPrograms, testFunc,
2109                                         caseDef);
2110         }
2111         group->addChild(formatGroup.release());
2112     }
2113 }
2114 
createSampledImageTestsInGroup(tcu::TestCaseGroup * group,PipelineConstructionType pipelineConstructionType)2115 void createSampledImageTestsInGroup(tcu::TestCaseGroup *group, PipelineConstructionType pipelineConstructionType)
2116 {
2117     addTestCasesWithFunctions(group, SampledImage::checkSupport, SampledImage::initPrograms, SampledImage::test,
2118                               pipelineConstructionType);
2119 }
2120 
createStorageImageTestsInGroup(tcu::TestCaseGroup * group,PipelineConstructionType pipelineConstructionType)2121 void createStorageImageTestsInGroup(tcu::TestCaseGroup *group, PipelineConstructionType pipelineConstructionType)
2122 {
2123     addTestCasesWithFunctions(group, StorageImage::checkSupport, StorageImage::initPrograms, StorageImage::test,
2124                               pipelineConstructionType);
2125 }
2126 
createStandardSamplePositionTestsInGroup(tcu::TestCaseGroup * group,PipelineConstructionType pipelineConstructionType)2127 void createStandardSamplePositionTestsInGroup(tcu::TestCaseGroup *group,
2128                                               PipelineConstructionType pipelineConstructionType)
2129 {
2130     addStandardSamplePositionTestCasesWithFunctions(group, StandardSamplePosition::checkSupport,
2131                                                     StandardSamplePosition::initPrograms, StandardSamplePosition::test,
2132                                                     pipelineConstructionType);
2133 }
2134 
2135 } // namespace
2136 
2137 //! Render to a multisampled image and sample from it in a fragment shader.
createMultisampleSampledImageTests(tcu::TestContext & testCtx,PipelineConstructionType pipelineConstructionType)2138 tcu::TestCaseGroup *createMultisampleSampledImageTests(tcu::TestContext &testCtx,
2139                                                        PipelineConstructionType pipelineConstructionType)
2140 {
2141     return createTestGroup(testCtx, "sampled_image", createSampledImageTestsInGroup, pipelineConstructionType);
2142 }
2143 
2144 //! Render to a multisampled image and access it with load/stores in a compute shader.
createMultisampleStorageImageTests(tcu::TestContext & testCtx,PipelineConstructionType pipelineConstructionType)2145 tcu::TestCaseGroup *createMultisampleStorageImageTests(tcu::TestContext &testCtx,
2146                                                        PipelineConstructionType pipelineConstructionType)
2147 {
2148     return createTestGroup(testCtx, "storage_image", createStorageImageTestsInGroup, pipelineConstructionType);
2149 }
2150 
2151 //! Render to a multisampled image and verify standard multisample positions.
createMultisampleStandardSamplePositionTests(tcu::TestContext & testCtx,PipelineConstructionType pipelineConstructionType)2152 tcu::TestCaseGroup *createMultisampleStandardSamplePositionTests(tcu::TestContext &testCtx,
2153                                                                  PipelineConstructionType pipelineConstructionType)
2154 {
2155     return createTestGroup(testCtx, "standardsampleposition", createStandardSamplePositionTestsInGroup,
2156                            pipelineConstructionType);
2157 }
2158 
2159 } // namespace pipeline
2160 } // namespace vkt
2161