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