1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2019 Advanced Micro Devices, Inc.
6 * Copyright (c) 2019 The Khronos Group Inc.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 *//*!
21 * \file
22 * \brief Tests for VK_AMD_mixed_attachment_samples
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktPipelineMultisampleMixedAttachmentSamplesTests.hpp"
26 #include "vktPipelineSampleLocationsUtil.hpp"
27 #include "vktPipelineMakeUtil.hpp"
28 #include "vktTestCase.hpp"
29 #include "vktTestCaseUtil.hpp"
30 #include "vktTestGroupUtil.hpp"
31
32 #include "vkCmdUtil.hpp"
33 #include "vkObjUtil.hpp"
34 #include "vkPlatform.hpp"
35 #include "vkMemUtil.hpp"
36 #include "vkQueryUtil.hpp"
37 #include "vkTypeUtil.hpp"
38 #include "vkRefUtil.hpp"
39 #include "vkBuilderUtil.hpp"
40 #include "vkPrograms.hpp"
41 #include "vkImageUtil.hpp"
42
43 #include "deUniquePtr.hpp"
44 #include "deSharedPtr.hpp"
45 #include "deRandom.hpp"
46 #include "deMath.h"
47
48 #include "tcuVector.hpp"
49 #include "tcuTestLog.hpp"
50 #include "tcuImageCompare.hpp"
51 #include "tcuTextureUtil.hpp"
52 #include "tcuRGBA.hpp"
53
54 #include <string>
55 #include <vector>
56
57 namespace vkt
58 {
59 namespace pipeline
60 {
61 namespace
62 {
63 using namespace vk;
64 using de::UniquePtr;
65 using de::MovePtr;
66 using de::SharedPtr;
67 using tcu::UVec2;
68 using tcu::Vec2;
69 using tcu::Vec4;
70
compareGreenImage(tcu::TestLog & log,const char * name,const char * description,const tcu::ConstPixelBufferAccess & image)71 bool compareGreenImage (tcu::TestLog& log, const char* name, const char* description, const tcu::ConstPixelBufferAccess& image)
72 {
73 tcu::TextureLevel greenImage(image.getFormat(), image.getWidth(), image.getHeight());
74 tcu::clear(greenImage.getAccess(), tcu::RGBA::green().toIVec());
75 return tcu::intThresholdCompare(log, name, description, greenImage.getAccess(), image, tcu::UVec4(2u), tcu::COMPARE_LOG_RESULT);
76 }
77
getImageAspectFlags(const VkFormat format)78 VkImageAspectFlags getImageAspectFlags (const VkFormat format)
79 {
80 const tcu::TextureFormat tcuFormat = mapVkFormat(format);
81
82 if (tcuFormat.order == tcu::TextureFormat::DS) return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
83 else if (tcuFormat.order == tcu::TextureFormat::D) return VK_IMAGE_ASPECT_DEPTH_BIT;
84 else if (tcuFormat.order == tcu::TextureFormat::S) return VK_IMAGE_ASPECT_STENCIL_BIT;
85
86 DE_ASSERT(false);
87 return 0u;
88 }
89
90 struct CompareData
91 {
92 Vec4 color;
93 float depth;
94 deUint32 stencil;
95
96 // Pad to 2*16 bytes, in the shader the base alignment of this structure is 16 due to vec4
97 deUint32 padding[2];
98
CompareDatavkt::pipeline::__anonc89cd22b0111::CompareData99 CompareData() : color(Vec4(0.0f)), depth(0.0f), stencil(0u)
100 {
101 padding[0] = 0u;
102 padding[1] = 0u;
103
104 static_assert(sizeof(CompareData) == (2 * 16), "Wrong structure size, expected 16 bytes");
105 }
106 };
107
108 //! Make a dummy sampler.
makeSampler(const DeviceInterface & vk,const VkDevice device)109 Move<VkSampler> makeSampler (const DeviceInterface& vk, const VkDevice device)
110 {
111 const VkSamplerCreateInfo samplerParams =
112 {
113 VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, // VkStructureType sType;
114 DE_NULL, // const void* pNext;
115 (VkSamplerCreateFlags)0, // VkSamplerCreateFlags flags;
116 VK_FILTER_NEAREST, // VkFilter magFilter;
117 VK_FILTER_NEAREST, // VkFilter minFilter;
118 VK_SAMPLER_MIPMAP_MODE_NEAREST, // VkSamplerMipmapMode mipmapMode;
119 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeU;
120 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeV;
121 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeW;
122 0.0f, // float mipLodBias;
123 VK_FALSE, // VkBool32 anisotropyEnable;
124 1.0f, // float maxAnisotropy;
125 VK_FALSE, // VkBool32 compareEnable;
126 VK_COMPARE_OP_ALWAYS, // VkCompareOp compareOp;
127 0.0f, // float minLod;
128 0.0f, // float maxLod;
129 VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // VkBorderColor borderColor;
130 VK_FALSE, // VkBool32 unnormalizedCoordinates;
131 };
132 return createSampler(vk, device, &samplerParams);
133 }
134
makeImage(const DeviceInterface & vk,const VkDevice device,const VkFormat format,const UVec2 & size,const VkSampleCountFlagBits samples,const VkImageUsageFlags usage)135 Move<VkImage> makeImage (const DeviceInterface& vk,
136 const VkDevice device,
137 const VkFormat format,
138 const UVec2& size,
139 const VkSampleCountFlagBits samples,
140 const VkImageUsageFlags usage)
141 {
142 const VkImageCreateInfo imageParams =
143 {
144 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
145 DE_NULL, // const void* pNext;
146 (VkImageCreateFlags)0, // VkImageCreateFlags flags;
147 VK_IMAGE_TYPE_2D, // VkImageType imageType;
148 format, // VkFormat format;
149 makeExtent3D(size.x(), size.y(), 1), // VkExtent3D extent;
150 1u, // deUint32 mipLevels;
151 1u, // deUint32 arrayLayers;
152 samples, // VkSampleCountFlagBits samples;
153 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
154 usage, // VkImageUsageFlags usage;
155 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
156 0u, // deUint32 queueFamilyIndexCount;
157 DE_NULL, // const deUint32* pQueueFamilyIndices;
158 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
159 };
160 return createImage(vk, device, &imageParams);
161 }
162
isDepthFormat(const VkFormat format)163 inline bool isDepthFormat (const VkFormat format)
164 {
165 return (getImageAspectFlags(format) & VK_IMAGE_ASPECT_DEPTH_BIT) != 0;
166 }
167
isStencilFormat(const VkFormat format)168 inline bool isStencilFormat (const VkFormat format)
169 {
170 return (getImageAspectFlags(format) & VK_IMAGE_ASPECT_STENCIL_BIT) != 0;
171 }
172
173 //! Create a test-specific MSAA pipeline
makeGraphicsPipeline(const DeviceInterface & vk,const VkDevice device,const VkPipelineLayout pipelineLayout,const VkRenderPass renderPass,const VkShaderModule vertexModule,const VkShaderModule fragmentModule,const bool useVertexInput,const deUint32 subpassNdx,const UVec2 & renderSize,const VkImageAspectFlags depthStencilAspect,const VkSampleCountFlagBits numSamples,const bool sampleShadingEnable,const VkSampleLocationsInfoEXT * pSampleLocationsInfo=DE_NULL)174 Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface& vk,
175 const VkDevice device,
176 const VkPipelineLayout pipelineLayout,
177 const VkRenderPass renderPass,
178 const VkShaderModule vertexModule,
179 const VkShaderModule fragmentModule,
180 const bool useVertexInput,
181 const deUint32 subpassNdx,
182 const UVec2& renderSize,
183 const VkImageAspectFlags depthStencilAspect, //!< Used to determine which D/S tests to turn on
184 const VkSampleCountFlagBits numSamples,
185 const bool sampleShadingEnable,
186 const VkSampleLocationsInfoEXT* pSampleLocationsInfo = DE_NULL)
187 {
188 std::vector<VkVertexInputBindingDescription> vertexInputBindingDescriptions;
189 std::vector<VkVertexInputAttributeDescription> vertexInputAttributeDescriptions;
190
191 // Vertex attributes: position and color
192 if (useVertexInput)
193 {
194 vertexInputBindingDescriptions.push_back (makeVertexInputBindingDescription (0u, 2 * sizeof(Vec4), VK_VERTEX_INPUT_RATE_VERTEX));
195 vertexInputAttributeDescriptions.push_back(makeVertexInputAttributeDescription(0u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, 0u));
196 vertexInputAttributeDescriptions.push_back(makeVertexInputAttributeDescription(1u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, sizeof(Vec4)));
197 }
198
199 const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo =
200 {
201 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
202 DE_NULL, // const void* pNext;
203 (VkPipelineVertexInputStateCreateFlags)0, // VkPipelineVertexInputStateCreateFlags flags;
204 static_cast<deUint32>(vertexInputBindingDescriptions.size()), // uint32_t vertexBindingDescriptionCount;
205 dataOrNullPtr(vertexInputBindingDescriptions), // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
206 static_cast<deUint32>(vertexInputAttributeDescriptions.size()), // uint32_t vertexAttributeDescriptionCount;
207 dataOrNullPtr(vertexInputAttributeDescriptions), // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
208 };
209
210 const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo =
211 {
212 VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
213 DE_NULL, // const void* pNext;
214 (VkPipelineInputAssemblyStateCreateFlags)0, // VkPipelineInputAssemblyStateCreateFlags flags;
215 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // VkPrimitiveTopology topology;
216 VK_FALSE, // VkBool32 primitiveRestartEnable;
217 };
218
219 const VkViewport viewport =
220 {
221 0.0f, 0.0f, // x, y
222 static_cast<float>(renderSize.x()), static_cast<float>(renderSize.y()), // widht, height
223 0.0f, 1.0f // minDepth, maxDepth
224 };
225
226 const VkRect2D scissor =
227 {
228 makeOffset2D(0, 0),
229 makeExtent2D(renderSize.x(), renderSize.y()),
230 };
231
232 const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo =
233 {
234 VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType;
235 DE_NULL, // const void* pNext;
236 (VkPipelineViewportStateCreateFlags)0, // VkPipelineViewportStateCreateFlags flags;
237 1u, // uint32_t viewportCount;
238 &viewport, // const VkViewport* pViewports;
239 1u, // uint32_t scissorCount;
240 &scissor, // const VkRect2D* pScissors;
241 };
242
243 const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo =
244 {
245 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
246 DE_NULL, // const void* pNext;
247 (VkPipelineRasterizationStateCreateFlags)0, // VkPipelineRasterizationStateCreateFlags flags;
248 VK_FALSE, // VkBool32 depthClampEnable;
249 VK_FALSE, // VkBool32 rasterizerDiscardEnable;
250 VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode;
251 VK_CULL_MODE_NONE, // VkCullModeFlags cullMode;
252 VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace;
253 VK_FALSE, // VkBool32 depthBiasEnable;
254 0.0f, // float depthBiasConstantFactor;
255 0.0f, // float depthBiasClamp;
256 0.0f, // float depthBiasSlopeFactor;
257 1.0f, // float lineWidth;
258 };
259
260 VkPipelineSampleLocationsStateCreateInfoEXT pipelineSampleLocationsCreateInfo =
261 {
262 VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT, // VkStructureType sType;
263 DE_NULL, // const void* pNext;
264 VK_TRUE, // VkBool32 sampleLocationsEnable;
265 VkSampleLocationsInfoEXT(), // VkSampleLocationsInfoEXT sampleLocationsInfo;
266 };
267
268 VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo =
269 {
270 VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
271 DE_NULL, // const void* pNext;
272 (VkPipelineMultisampleStateCreateFlags)0, // VkPipelineMultisampleStateCreateFlags flags;
273 numSamples, // VkSampleCountFlagBits rasterizationSamples;
274 sampleShadingEnable, // VkBool32 sampleShadingEnable;
275 1.0f, // float minSampleShading;
276 DE_NULL, // const VkSampleMask* pSampleMask;
277 VK_FALSE, // VkBool32 alphaToCoverageEnable;
278 VK_FALSE // VkBool32 alphaToOneEnable;
279 };
280
281 if (pSampleLocationsInfo)
282 {
283 pipelineSampleLocationsCreateInfo.sampleLocationsInfo = *pSampleLocationsInfo;
284 pipelineMultisampleStateInfo.pNext = &pipelineSampleLocationsCreateInfo;
285 }
286
287 // Simply increment the buffer
288 const VkStencilOpState stencilOpState = makeStencilOpState(
289 VK_STENCIL_OP_KEEP, // stencil fail
290 VK_STENCIL_OP_INCREMENT_AND_CLAMP, // depth & stencil pass
291 VK_STENCIL_OP_KEEP, // depth only fail
292 VK_COMPARE_OP_ALWAYS, // compare op
293 ~0u, // compare mask
294 ~0u, // write mask
295 0u); // reference
296
297 // Always pass the depth test
298 VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo =
299 {
300 VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
301 DE_NULL, // const void* pNext;
302 (VkPipelineDepthStencilStateCreateFlags)0, // VkPipelineDepthStencilStateCreateFlags flags;
303 (depthStencilAspect & VK_IMAGE_ASPECT_DEPTH_BIT) != 0u, // VkBool32 depthTestEnable;
304 VK_TRUE, // VkBool32 depthWriteEnable;
305 VK_COMPARE_OP_ALWAYS, // VkCompareOp depthCompareOp;
306 VK_FALSE, // VkBool32 depthBoundsTestEnable;
307 (depthStencilAspect & VK_IMAGE_ASPECT_STENCIL_BIT) != 0u, // VkBool32 stencilTestEnable;
308 stencilOpState, // VkStencilOpState front;
309 stencilOpState, // VkStencilOpState back;
310 0.0f, // float minDepthBounds;
311 1.0f, // float maxDepthBounds;
312 };
313
314 const VkColorComponentFlags colorComponentsAll = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
315 const VkPipelineColorBlendAttachmentState defaultBlendAttachmentState =
316 {
317 VK_FALSE, // VkBool32 blendEnable;
318 VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor;
319 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor;
320 VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp;
321 VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor;
322 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor;
323 VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp;
324 colorComponentsAll, // VkColorComponentFlags colorWriteMask;
325 };
326
327 const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo =
328 {
329 VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
330 DE_NULL, // const void* pNext;
331 (VkPipelineColorBlendStateCreateFlags)0, // VkPipelineColorBlendStateCreateFlags flags;
332 VK_FALSE, // VkBool32 logicOpEnable;
333 VK_LOGIC_OP_COPY, // VkLogicOp logicOp;
334 1u, // deUint32 attachmentCount;
335 &defaultBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
336 { 0.0f, 0.0f, 0.0f, 0.0f }, // float blendConstants[4];
337 };
338
339 const VkPipelineShaderStageCreateInfo pShaderStages[] =
340 {
341 {
342 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
343 DE_NULL, // const void* pNext;
344 (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags;
345 VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlagBits stage;
346 vertexModule, // VkShaderModule module;
347 "main", // const char* pName;
348 DE_NULL, // const VkSpecializationInfo* pSpecializationInfo;
349 },
350 {
351 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
352 DE_NULL, // const void* pNext;
353 (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags;
354 VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlagBits stage;
355 fragmentModule, // VkShaderModule module;
356 "main", // const char* pName;
357 DE_NULL, // const VkSpecializationInfo* pSpecializationInfo;
358 }
359 };
360
361 const VkGraphicsPipelineCreateInfo graphicsPipelineInfo =
362 {
363 VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType;
364 DE_NULL, // const void* pNext;
365 (VkPipelineCreateFlags)0, // VkPipelineCreateFlags flags;
366 DE_LENGTH_OF_ARRAY(pShaderStages), // deUint32 stageCount;
367 pShaderStages, // const VkPipelineShaderStageCreateInfo* pStages;
368 &vertexInputStateInfo, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState;
369 &pipelineInputAssemblyStateInfo, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState;
370 DE_NULL, // const VkPipelineTessellationStateCreateInfo* pTessellationState;
371 &pipelineViewportStateInfo, // const VkPipelineViewportStateCreateInfo* pViewportState;
372 &pipelineRasterizationStateInfo, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState;
373 &pipelineMultisampleStateInfo, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
374 &pipelineDepthStencilStateInfo, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState;
375 &pipelineColorBlendStateInfo, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState;
376 DE_NULL, // const VkPipelineDynamicStateCreateInfo* pDynamicState;
377 pipelineLayout, // VkPipelineLayout layout;
378 renderPass, // VkRenderPass renderPass;
379 subpassNdx, // deUint32 subpass;
380 DE_NULL, // VkPipeline basePipelineHandle;
381 -1, // deInt32 basePipelineIndex;
382 };
383
384 return createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineInfo);
385 }
386
387 //! Wrap float after an increment
wrapIncFloat(float a,float min,float max)388 inline float wrapIncFloat (float a, float min, float max)
389 {
390 return deFloatMax(min, deFloatMod(a, max));
391 }
392
393 //! Generate expected data for color, depth, and stencil samples of a given image.
394 //! Samples are ordered starting at pixel (0, 0) - see compute shader source for reference.
generateCompareData(const deUint32 seed,const UVec2 & imageSize,const deUint32 numCoverageSamples,const deUint32 numColorSamples,const deUint32 numDepthStencilSamples)395 std::vector<CompareData> generateCompareData (const deUint32 seed,
396 const UVec2& imageSize,
397 const deUint32 numCoverageSamples,
398 const deUint32 numColorSamples,
399 const deUint32 numDepthStencilSamples)
400 {
401 std::vector<CompareData> allData;
402 de::Random rng (seed);
403
404 for (deUint32 y = 0u; y < imageSize.y(); ++y)
405 for (deUint32 x = 0u; x < imageSize.x(); ++x)
406 for (deUint32 sample = 0u; sample < numCoverageSamples; ++sample)
407 {
408 CompareData cd;
409
410 if (sample < numColorSamples)
411 {
412 for (int i = 0; i < 3; ++i)
413 cd.color[i] = 0.1f * static_cast<float>(rng.getInt(1, 10));
414
415 cd.color.w() = 1.0f;
416 }
417
418 if (sample < numDepthStencilSamples)
419 {
420 const deUint32 globalSample = sample + numColorSamples * (x + imageSize.x() * y);
421 cd.depth = wrapIncFloat(0.05f * static_cast<float>(1 + globalSample), 0.05f, 1.0f);
422 cd.stencil = 1 + globalSample % numCoverageSamples;
423 }
424
425 allData.push_back(cd);
426 }
427
428 return allData;
429 }
430
431 //! NDC transformation algorithm for sample locations
432 template<typename SampleAccessor>
ndcTransformEachSampleInPixel(const UVec2 & framebufferSize,const deUint32 numSamplesPerPixel,const SampleAccessor & access)433 std::vector<Vec2> ndcTransformEachSampleInPixel (const UVec2& framebufferSize, const deUint32 numSamplesPerPixel, const SampleAccessor& access)
434 {
435 std::vector<Vec2> locations;
436
437 for (deUint32 y = 0; y < framebufferSize.y(); ++y)
438 for (deUint32 x = 0; x < framebufferSize.x(); ++x)
439 for (deUint32 sampleNdx = 0; sampleNdx < numSamplesPerPixel; ++sampleNdx)
440 {
441 const Vec2& sp = access(x, y, sampleNdx);
442 const float globalX = sp.x() + static_cast<float>(x);
443 const float globalY = sp.y() + static_cast<float>(y);
444
445 // Transform to [-1, 1] space
446 locations.push_back(Vec2(-1.0f + 2.0f * (globalX / static_cast<float>(framebufferSize.x())),
447 -1.0f + 2.0f * (globalY / static_cast<float>(framebufferSize.y()))));
448 }
449
450 return locations;
451 }
452
453 class AccessStandardSampleLocationsArray
454 {
455 public:
AccessStandardSampleLocationsArray(const Vec2 * ptr)456 AccessStandardSampleLocationsArray (const Vec2* ptr) : m_pData (ptr) {}
457
operator ()(const deUint32 x,const deUint32 y,const deUint32 sampleNdx) const458 const Vec2& operator ()(const deUint32 x, const deUint32 y, const deUint32 sampleNdx) const
459 {
460 DE_UNREF(x);
461 DE_UNREF(y);
462 return m_pData[sampleNdx];
463 }
464
465 private:
466 const Vec2* m_pData;
467 };
468
469 class AccessMultisamplePixelGrid
470 {
471 public:
AccessMultisamplePixelGrid(const MultisamplePixelGrid * ptr)472 AccessMultisamplePixelGrid (const MultisamplePixelGrid* ptr) : m_pGrid (ptr) {}
473
operator ()(const deUint32 x,const deUint32 y,const deUint32 sampleNdx) const474 Vec2 operator ()(const deUint32 x, const deUint32 y, const deUint32 sampleNdx) const
475 {
476 const VkSampleLocationEXT& sp = m_pGrid->getSample(x, y, sampleNdx);
477 return Vec2(sp.x, sp.y);
478 }
479
480 private:
481 const MultisamplePixelGrid* m_pGrid;
482 };
483
484 //! Generate NDC space standard sample locations at each framebuffer pixel
485 //! Data is filled starting at pixel (0,0) and for each pixel there are numSamples samples
genFramebufferStandardSampleLocations(const VkSampleCountFlagBits numSamples,const UVec2 & framebufferSize)486 std::vector<Vec2> genFramebufferStandardSampleLocations (const VkSampleCountFlagBits numSamples, const UVec2& framebufferSize)
487 {
488 static const Vec2 s_location_samples_1[] =
489 {
490 Vec2(0.5f, 0.5f),
491 };
492 static const Vec2 s_location_samples_2[] =
493 {
494 Vec2(0.75f, 0.75f),
495 Vec2(0.25f, 0.25f),
496 };
497 static const Vec2 s_location_samples_4[] =
498 {
499 Vec2(0.375f, 0.125f),
500 Vec2(0.875f, 0.375f),
501 Vec2(0.125f, 0.625f),
502 Vec2(0.625f, 0.875f),
503 };
504 static const Vec2 s_location_samples_8[] =
505 {
506 Vec2(0.5625f, 0.3125f),
507 Vec2(0.4375f, 0.6875f),
508 Vec2(0.8125f, 0.5625f),
509 Vec2(0.3125f, 0.1875f),
510 Vec2(0.1875f, 0.8125f),
511 Vec2(0.0625f, 0.4375f),
512 Vec2(0.6875f, 0.9375f),
513 Vec2(0.9375f, 0.0625f),
514 };
515 static const Vec2 s_location_samples_16[] =
516 {
517 Vec2(0.5625f, 0.5625f),
518 Vec2(0.4375f, 0.3125f),
519 Vec2(0.3125f, 0.6250f),
520 Vec2(0.7500f, 0.4375f),
521 Vec2(0.1875f, 0.3750f),
522 Vec2(0.6250f, 0.8125f),
523 Vec2(0.8125f, 0.6875f),
524 Vec2(0.6875f, 0.1875f),
525 Vec2(0.3750f, 0.8750f),
526 Vec2(0.5000f, 0.0625f),
527 Vec2(0.2500f, 0.1250f),
528 Vec2(0.1250f, 0.7500f),
529 Vec2(0.0000f, 0.5000f),
530 Vec2(0.9375f, 0.2500f),
531 Vec2(0.8750f, 0.9375f),
532 Vec2(0.0625f, 0.0000f),
533 };
534
535 const Vec2* pSampleLocation = DE_NULL;
536
537 switch (numSamples)
538 {
539 case VK_SAMPLE_COUNT_1_BIT: pSampleLocation = s_location_samples_1; break;
540 case VK_SAMPLE_COUNT_2_BIT: pSampleLocation = s_location_samples_2; break;
541 case VK_SAMPLE_COUNT_4_BIT: pSampleLocation = s_location_samples_4; break;
542 case VK_SAMPLE_COUNT_8_BIT: pSampleLocation = s_location_samples_8; break;
543 case VK_SAMPLE_COUNT_16_BIT: pSampleLocation = s_location_samples_16; break;
544
545 default:
546 DE_ASSERT(0);
547 return std::vector<Vec2>();
548 }
549
550 return ndcTransformEachSampleInPixel(framebufferSize, static_cast<deUint32>(numSamples), AccessStandardSampleLocationsArray(pSampleLocation));
551 }
552
553 //! Generate NDC space custom sample locations at each framebuffer pixel, based on the given pixel grid
getSampleLocations(const MultisamplePixelGrid & pixelGrid,const UVec2 & framebufferSize)554 std::vector<Vec2> getSampleLocations (const MultisamplePixelGrid& pixelGrid, const UVec2& framebufferSize)
555 {
556 return ndcTransformEachSampleInPixel(framebufferSize, pixelGrid.samplesPerPixel(), AccessMultisamplePixelGrid(&pixelGrid));
557 }
558
559 struct PositionColor
560 {
561 tcu::Vec4 position;
562 tcu::Vec4 color;
563
PositionColorvkt::pipeline::__anonc89cd22b0111::PositionColor564 PositionColor (const tcu::Vec4& pos, const tcu::Vec4& col) : position(pos), color(col) {}
565 };
566
567 //! Generate subpixel triangles containing the sample position, based on compare data.
568 //! Stencil values are created by overlapping triangles, so the stencil pipeline state must be set up accordingly.
generateSubpixelTriangles(const UVec2 & renderSize,const std::vector<CompareData> & compareData,const std::vector<Vec2> & sampleLocations)569 std::vector<PositionColor> generateSubpixelTriangles (const UVec2& renderSize,
570 const std::vector<CompareData>& compareData,
571 const std::vector<Vec2>& sampleLocations)
572 {
573 std::vector<PositionColor> vertices;
574
575 // For each sample location (in the whole framebuffer), create a sub-pixel triangle that contains it.
576 // NDC viewport size is 2.0 in X and Y and NDC pixel width/height depends on the framebuffer resolution.
577 const Vec2 pixelSize = Vec2(2.0f) / renderSize.cast<float>();
578 const Vec2 offset = pixelSize / 16.0f; // 4 bits precision
579
580 // Surround with a roughly centered triangle
581 const float y1 = 0.5f * offset.y();
582 const float y2 = 0.35f * offset.y();
583 const float x1 = 0.5f * offset.x();
584
585 DE_ASSERT(compareData.size() == sampleLocations.size());
586
587 for (std::size_t globalSampleNdx = 0; globalSampleNdx < sampleLocations.size(); ++globalSampleNdx)
588 {
589 const Vec2& loc = sampleLocations[globalSampleNdx];
590 const CompareData& cd = compareData [globalSampleNdx];
591
592 // Overdraw at the same position to get the desired stencil
593 // Draw at least once, if stencil is 0
594 for (deUint32 i = 0; i < deMaxu32(1u, cd.stencil); ++i)
595 {
596 vertices.push_back(PositionColor(Vec4(loc.x(), loc.y() - y1, cd.depth, 1.0f), cd.color));
597 vertices.push_back(PositionColor(Vec4(loc.x() - x1, loc.y() + y2, cd.depth, 1.0f), cd.color));
598 vertices.push_back(PositionColor(Vec4(loc.x() + x1, loc.y() + y2, cd.depth, 1.0f), cd.color));
599 }
600 }
601
602 return vertices;
603 }
604
reportSampleError(tcu::TestLog & log,const std::string & sampleDesc,UVec2 & renderSize,const deUint32 numCoverageSamples,const deUint32 globalSampleNdx)605 void reportSampleError (tcu::TestLog& log, const std::string& sampleDesc, UVec2& renderSize, const deUint32 numCoverageSamples, const deUint32 globalSampleNdx)
606 {
607 const deUint32 pixelNdx = globalSampleNdx / numCoverageSamples;
608 const deUint32 x = pixelNdx % renderSize.x();
609 const deUint32 y = pixelNdx / renderSize.x();
610 const deUint32 sample = globalSampleNdx % numCoverageSamples;
611
612 log << tcu::TestLog::Message << "Incorrect " << sampleDesc << " sample (" << sample << ") at pixel (" << x << ", " << y << ")" << tcu::TestLog::EndMessage;
613 }
614
checkSampleRequirements(Context & context,const VkSampleCountFlagBits numColorSamples,const VkSampleCountFlagBits numDepthStencilSamples,const bool requireStandardSampleLocations)615 void checkSampleRequirements (Context& context,
616 const VkSampleCountFlagBits numColorSamples,
617 const VkSampleCountFlagBits numDepthStencilSamples,
618 const bool requireStandardSampleLocations)
619 {
620 const VkPhysicalDeviceLimits& limits = context.getDeviceProperties().limits;
621
622 if ((limits.framebufferColorSampleCounts & numColorSamples) == 0u)
623 TCU_THROW(NotSupportedError, "framebufferColorSampleCounts: sample count not supported");
624
625 if ((limits.framebufferDepthSampleCounts & numDepthStencilSamples) == 0u)
626 TCU_THROW(NotSupportedError, "framebufferDepthSampleCounts: sample count not supported");
627
628 if ((limits.framebufferStencilSampleCounts & numDepthStencilSamples) == 0u)
629 TCU_THROW(NotSupportedError, "framebufferStencilSampleCounts: sample count not supported");
630
631 if ((limits.sampledImageColorSampleCounts & numColorSamples) == 0u)
632 TCU_THROW(NotSupportedError, "sampledImageColorSampleCounts: sample count not supported");
633
634 if ((limits.sampledImageDepthSampleCounts & numDepthStencilSamples) == 0u)
635 TCU_THROW(NotSupportedError, "sampledImageDepthSampleCounts: sample count not supported");
636
637 if ((limits.sampledImageStencilSampleCounts & numDepthStencilSamples) == 0u)
638 TCU_THROW(NotSupportedError, "sampledImageStencilSampleCounts: sample count not supported");
639
640 // This is required to output geometry that is covering a specific sample
641 if (requireStandardSampleLocations && !limits.standardSampleLocations)
642 TCU_THROW(NotSupportedError, "standardSampleLocations: not supported");
643 }
644
checkImageRequirements(Context & context,const VkFormat format,const VkFormatFeatureFlags requiredFeatureFlags,const VkImageUsageFlags requiredUsageFlags,const VkSampleCountFlagBits requiredSampleCount=VK_SAMPLE_COUNT_1_BIT)645 void checkImageRequirements (Context& context,
646 const VkFormat format,
647 const VkFormatFeatureFlags requiredFeatureFlags,
648 const VkImageUsageFlags requiredUsageFlags,
649 const VkSampleCountFlagBits requiredSampleCount = VK_SAMPLE_COUNT_1_BIT)
650 {
651 const InstanceInterface& vki = context.getInstanceInterface();
652 const VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
653 VkImageFormatProperties imageProperties;
654
655 const VkFormatProperties formatProperties = getPhysicalDeviceFormatProperties(vki, physicalDevice, format);
656
657 if ((formatProperties.optimalTilingFeatures & requiredFeatureFlags) != requiredFeatureFlags)
658 TCU_THROW(NotSupportedError, (de::toString(format) + ": format features not supported").c_str());
659
660 const VkResult result = vki.getPhysicalDeviceImageFormatProperties(physicalDevice, format, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, requiredUsageFlags, (VkImageCreateFlags)0, &imageProperties);
661
662 if (result == VK_ERROR_FORMAT_NOT_SUPPORTED)
663 TCU_THROW(NotSupportedError, (de::toString(format) + ": format not supported").c_str());
664
665 if ((imageProperties.sampleCounts & requiredSampleCount) != requiredSampleCount)
666 TCU_THROW(NotSupportedError, (de::toString(format) + ": sample count not supported").c_str());
667 }
668
669 //! Used after a render pass color output (draw or resolve)
recordCopyOutputImageToBuffer(const DeviceInterface & vk,const VkCommandBuffer cmdBuffer,const UVec2 & imageSize,const VkImage srcImage,const VkBuffer dstBuffer)670 void recordCopyOutputImageToBuffer (const DeviceInterface& vk,
671 const VkCommandBuffer cmdBuffer,
672 const UVec2& imageSize,
673 const VkImage srcImage,
674 const VkBuffer dstBuffer)
675 {
676 // Image read barrier after color output
677 {
678 const VkImageMemoryBarrier barrier =
679 {
680 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
681 DE_NULL, // const void* pNext;
682 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask;
683 VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags dstAccessMask;
684 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout oldLayout;
685 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout newLayout;
686 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
687 VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex;
688 srcImage, // VkImage image;
689 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u), // VkImageSubresourceRange subresourceRange;
690 };
691
692 vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0u, DE_NULL, 0u, DE_NULL, 1u, &barrier);
693 }
694 // Resolve image -> host buffer
695 {
696 const VkBufferImageCopy region =
697 {
698 0ull, // VkDeviceSize bufferOffset;
699 0u, // uint32_t bufferRowLength;
700 0u, // uint32_t bufferImageHeight;
701 makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u), // VkImageSubresourceLayers imageSubresource;
702 makeOffset3D(0, 0, 0), // VkOffset3D imageOffset;
703 makeExtent3D(imageSize.x(), imageSize.y(), 1u), // VkExtent3D imageExtent;
704 };
705
706 vk.cmdCopyImageToBuffer(cmdBuffer, srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dstBuffer, 1u, ®ion);
707 }
708 // Buffer write barrier
709 {
710 const VkBufferMemoryBarrier barrier =
711 {
712 VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType;
713 DE_NULL, // const void* pNext;
714 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask;
715 VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask;
716 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
717 VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex;
718 dstBuffer, // VkBuffer buffer;
719 0ull, // VkDeviceSize offset;
720 VK_WHOLE_SIZE, // VkDeviceSize size;
721 };
722
723 vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0,
724 0u, DE_NULL, 1u, &barrier, DE_NULL, 0u);
725 }
726 }
727
728 namespace VerifySamples
729 {
730
731 //! The parameters that define a test case
732 struct TestParams
733 {
734 struct SampleCount
735 {
736 VkSampleCountFlagBits numCoverageSamples; //!< VkPipelineMultisampleStateCreateInfo::rasterizationSamples
737 VkSampleCountFlagBits numColorSamples; //!< VkAttachmentDescription::samples and VkImageCreateInfo::samples
738 VkSampleCountFlagBits numDepthStencilSamples; //!< VkAttachmentDescription::samples and VkImageCreateInfo::samples
739 };
740
741 VkFormat colorFormat; //!< Color attachment format
742 VkFormat depthStencilFormat; //!< D/S attachment format. Will test both aspects if it's a mixed format
743 bool useProgrammableSampleLocations; //!< Try to use VK_EXT_sample_locations if available
744 std::vector<SampleCount> perSubpassSamples; //!< Will use multiple subpasses if more than one element
745
TestParamsvkt::pipeline::__anonc89cd22b0111::VerifySamples::TestParams746 TestParams (void)
747 : colorFormat ()
748 , depthStencilFormat ()
749 , useProgrammableSampleLocations ()
750 {
751 }
752 };
753
754 //! Common data used by the test
755 struct WorkingData
756 {
757 struct PerSubpass
758 {
759 deUint32 numVertices; //!< Number of vertices defined in the vertex buffer
760 Move<VkBuffer> vertexBuffer;
761 MovePtr<Allocation> vertexBufferAlloc;
762 Move<VkImage> colorImage; //!< Color image
763 Move<VkImageView> colorImageView; //!< Color attachment
764 MovePtr<Allocation> colorImageAlloc;
765 Move<VkImage> depthStencilImage; //!< Depth stencil image
766 Move<VkImageView> depthStencilImageView; //!< Depth stencil attachment
767 Move<VkImageView> depthOnlyImageView; //!< Depth aspect for shader read
768 Move<VkImageView> stencilOnlyImageView; //!< Stencil aspect for shader read
769 MovePtr<Allocation> depthStencilImageAlloc;
770 Move<VkBuffer> compareBuffer; //!< Buffer used to verify the images - comparison data
771 MovePtr<Allocation> compareBufferAlloc;
772 VkDeviceSize compareBufferSize;
773 Move<VkBuffer> resultBuffer; //!< Buffer used to verify the images - results
774 MovePtr<Allocation> resultBufferAlloc;
775 VkDeviceSize resultBufferSize;
776 deUint32 numResultElements; //!< Number of checksums in the result buffer
777 MovePtr<MultisamplePixelGrid> pixelGrid; //!< Programmable locations
778
PerSubpassvkt::pipeline::__anonc89cd22b0111::VerifySamples::WorkingData::PerSubpass779 PerSubpass (void)
780 : numVertices ()
781 , compareBufferSize ()
782 , resultBufferSize ()
783 , numResultElements ()
784 {
785 }
786 };
787
788 UVec2 renderSize; //!< Size of the framebuffer
789 VkPhysicalDeviceSampleLocationsPropertiesEXT sampleLocationsProperties; //!< Used with VK_EXT_sample_locations
790
791 std::vector<de::SharedPtr<PerSubpass> > perSubpass; //!< Test may use more than one set of data
792
WorkingDatavkt::pipeline::__anonc89cd22b0111::VerifySamples::WorkingData793 WorkingData (void)
794 : sampleLocationsProperties ()
795 {
796 }
797 };
798
addVerificationComputeShader(SourceCollections & programCollection,const VkSampleCountFlagBits numCoverageSamples,const VkSampleCountFlagBits numColorSamples,const VkSampleCountFlagBits numDepthStencilSamples,const VkFormat depthStencilFormat,const std::string & nameSuffix)799 void addVerificationComputeShader (SourceCollections& programCollection,
800 const VkSampleCountFlagBits numCoverageSamples,
801 const VkSampleCountFlagBits numColorSamples,
802 const VkSampleCountFlagBits numDepthStencilSamples,
803 const VkFormat depthStencilFormat,
804 const std::string& nameSuffix)
805 {
806 const bool isColorMS = (numColorSamples != VK_SAMPLE_COUNT_1_BIT);
807 const bool isDepthStencilMS = (numDepthStencilSamples != VK_SAMPLE_COUNT_1_BIT);
808 const std::string colorBit = de::toString(static_cast<deUint32>(VK_IMAGE_ASPECT_COLOR_BIT)) + "u";
809 const std::string depthBit = de::toString(static_cast<deUint32>(VK_IMAGE_ASPECT_DEPTH_BIT)) + "u";
810 const std::string stencilBit = de::toString(static_cast<deUint32>(VK_IMAGE_ASPECT_STENCIL_BIT)) + "u";
811
812 std::ostringstream src;
813 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
814 << "\n"
815 << "struct CompareData {\n"
816 << " vec4 color;\n"
817 << " float depth;\n"
818 << " uint stencil;\n"
819 << "};\n"
820 << "\n"
821 << "layout(local_size_x = " << static_cast<deUint32>(numCoverageSamples) << ") in;\n"
822 // Always use this descriptor layout and ignore unused bindings
823 << "layout(set = 0, binding = 0, std430) writeonly buffer Output {\n"
824 << " uint values[];\n"
825 << "} sb_out;\n"
826 << "layout(set = 0, binding = 1, std430) readonly buffer InputCompare {\n"
827 << " CompareData data[];\n"
828 << "} sb_cmp;\n"
829 << "layout(set = 0, binding = 2) uniform sampler2D" << (isColorMS ? "MS" : "") << " colorImage;\n"
830 << "layout(set = 0, binding = 3) uniform sampler2D" << (isDepthStencilMS ? "MS" : "") <<" depthImage;\n"
831 << "layout(set = 0, binding = 4) uniform usampler2D" << (isDepthStencilMS ? "MS" : "") <<" stencilImage;\n"
832 << "\n"
833 << "void main (void)\n"
834 << "{\n"
835
836 // Data for each sample in each pixel is laid out linearly (e.g 2 samples):
837 // [pixel(0, 0) sample(0)][pixel(0, 0) sample(1)][pixel(1, 0) sample(0)][pixel(1, 0) sample(1)]...
838
839 << " uint globalIndex = gl_LocalInvocationID.x + gl_WorkGroupSize.x * (gl_WorkGroupID.x + gl_WorkGroupID.y * gl_NumWorkGroups.x);\n"
840 << " ivec2 position = ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y);\n"
841 << " int sampleNdx = int(gl_LocalInvocationID.x);\n"
842 << " uint result = 0u;\n"
843 << "\n"
844 << " // Verify color samples\n"
845 << " if (sampleNdx < " << static_cast<deUint32>(numColorSamples) << ")\n"
846 << " {\n"
847 << " vec4 color = texelFetch(colorImage, position, sampleNdx);\n" // for non-MS (1 sample) case, sampleNdx = 0 and will instead be LOD = 0
848 << " vec4 diff = abs(color - sb_cmp.data[globalIndex].color);\n"
849 << " vec4 threshold = vec4(0.02);\n"
850 << "\n"
851 << " if (all(lessThan(diff, threshold)))\n"
852 << " result |= " << colorBit << ";\n"
853 << " }\n"
854 << " else\n"
855 << " result |= " << colorBit << ";\n" // Pass, if sample doesn't exist
856 << "\n";
857
858 if (isDepthFormat(depthStencilFormat))
859 {
860 src << " // Verify depth samples\n"
861 << " if (sampleNdx < " << static_cast<deUint32>(numDepthStencilSamples) << ")\n"
862 << " {\n"
863 << " float depth = texelFetch(depthImage, position, sampleNdx).r;\n"
864 << " float diff = abs(depth - sb_cmp.data[globalIndex].depth);\n"
865 << " float threshold = 0.002;\n"
866 << "\n"
867 << " if (diff < threshold)\n"
868 << " result |= " << depthBit << ";\n"
869 << " }\n"
870 << " else\n"
871 << " result |= " << depthBit << ";\n"
872 << "\n";
873 }
874
875 if (isStencilFormat(depthStencilFormat))
876 {
877 src << " // Verify stencil samples\n"
878 << " if (sampleNdx < " << static_cast<deUint32>(numDepthStencilSamples) << ")\n"
879 << " {\n"
880 << " uint stencil = texelFetch(stencilImage, position, sampleNdx).r;\n"
881 << " uint diff = stencil - sb_cmp.data[globalIndex].stencil;\n"
882 << "\n"
883 << " if (diff == 0u)\n"
884 << " result |= " << stencilBit << ";\n"
885 << " }\n"
886 << " else\n"
887 << " result |= " << stencilBit << ";\n"
888 << "\n";
889 }
890
891 src << " sb_out.values[globalIndex] = result;\n"
892 << "}\n";
893 programCollection.glslSources.add("comp" + nameSuffix) << glu::ComputeSource(src.str());
894 }
895
896 //! Get a compact sample count string in format X_Y_Z
getSampleCountString(const TestParams::SampleCount & samples)897 std::string getSampleCountString (const TestParams::SampleCount& samples)
898 {
899 std::ostringstream str;
900
901 str << static_cast<deUint32>(samples.numCoverageSamples) << "_"
902 << static_cast<deUint32>(samples.numColorSamples) << "_"
903 << static_cast<deUint32>(samples.numDepthStencilSamples);
904
905 return str.str();
906 }
907
initPrograms(SourceCollections & programCollection,const TestParams params)908 void initPrograms (SourceCollections& programCollection, const TestParams params)
909 {
910 // Vertex shader - position and color
911 {
912 std::ostringstream src;
913 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
914 << "\n"
915 << "layout(location = 0) in vec4 in_position;\n"
916 << "layout(location = 1) in vec4 in_color;\n"
917 << "layout(location = 0) out vec4 o_color;\n"
918 << "\n"
919 << "out gl_PerVertex {\n"
920 << " vec4 gl_Position;\n"
921 << "};\n"
922 << "\n"
923 << "void main(void)\n"
924 << "{\n"
925 << " gl_Position = in_position;\n"
926 << " o_color = in_color;\n"
927 << "}\n";
928
929 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
930 }
931
932 // Fragment shader - output color from VS
933 {
934 std::ostringstream src;
935 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
936 << "\n"
937 << "layout(location = 0) in vec4 in_color;\n"
938 << "layout(location = 0) out vec4 o_color;\n"
939 << "\n"
940 << "void main(void)\n"
941 << "{\n"
942 << " o_color = in_color;\n"
943 << "}\n";
944
945 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
946 }
947
948 // Compute shader - image verification
949 for (deUint32 subpassNdx = 0; subpassNdx < static_cast<deUint32>(params.perSubpassSamples.size()); ++subpassNdx)
950 {
951 const TestParams::SampleCount& samples = params.perSubpassSamples[subpassNdx];
952 addVerificationComputeShader(programCollection,
953 samples.numCoverageSamples,
954 samples.numColorSamples,
955 samples.numDepthStencilSamples,
956 params.depthStencilFormat,
957 "_" + getSampleCountString(samples));
958 }
959 }
960
961 //! A simple color, depth/stencil draw. Subpasses (if more than one) are independent
draw(Context & context,const TestParams & params,WorkingData & wd)962 void draw (Context& context, const TestParams& params, WorkingData& wd)
963 {
964 const DeviceInterface& vk = context.getDeviceInterface();
965 const VkDevice device = context.getDevice();
966 const deUint32 numSubpasses = static_cast<deUint32>(wd.perSubpass.size());
967
968 Move<VkRenderPass> renderPass;
969 Move<VkFramebuffer> framebuffer;
970 std::vector<VkSampleLocationsInfoEXT> perSubpassSampleLocationsInfo;
971 std::vector<VkAttachmentSampleLocationsEXT> attachmentSampleLocations;
972 std::vector<VkSubpassSampleLocationsEXT> subpassSampleLocations;
973
974 if (params.useProgrammableSampleLocations)
975 for (deUint32 subpassNdx = 0; subpassNdx < numSubpasses; ++subpassNdx)
976 {
977 perSubpassSampleLocationsInfo.push_back(makeSampleLocationsInfo(*wd.perSubpass[subpassNdx]->pixelGrid));
978 }
979
980 // Create a render pass and a framebuffer
981 {
982 std::vector<VkSubpassDescription> subpasses;
983 std::vector<VkImageView> attachments;
984 std::vector<VkAttachmentDescription> attachmentDescriptions;
985 std::vector<VkAttachmentReference> attachmentReferences;
986
987 // Reserve capacity to avoid invalidating pointers to elements
988 attachmentReferences.reserve(numSubpasses * 2);
989
990 for (deUint32 subpassNdx = 0; subpassNdx < numSubpasses; ++subpassNdx)
991 {
992 attachments.push_back(wd.perSubpass[subpassNdx]->colorImageView.get());
993 attachments.push_back(wd.perSubpass[subpassNdx]->depthStencilImageView.get());
994
995 attachmentDescriptions.push_back(makeAttachmentDescription(
996 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags;
997 params.colorFormat, // VkFormat format;
998 params.perSubpassSamples[subpassNdx].numColorSamples, // VkSampleCountFlagBits samples;
999 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
1000 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
1001 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
1002 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
1003 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
1004 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL // VkImageLayout finalLayout;
1005 ));
1006
1007 attachmentDescriptions.push_back(makeAttachmentDescription(
1008 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags;
1009 params.depthStencilFormat, // VkFormat format;
1010 params.perSubpassSamples[subpassNdx].numDepthStencilSamples, // VkSampleCountFlagBits samples;
1011 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
1012 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
1013 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp stencilLoadOp;
1014 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp stencilStoreOp;
1015 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
1016 VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL // VkImageLayout finalLayout;
1017 ));
1018
1019 attachmentReferences.push_back(makeAttachmentReference(static_cast<deUint32>(attachmentReferences.size()), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
1020 const VkAttachmentReference* colorRef = &attachmentReferences.back();
1021
1022 attachmentReferences.push_back(makeAttachmentReference(static_cast<deUint32>(attachmentReferences.size()), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL));
1023 const VkAttachmentReference* depthStencilRef = &attachmentReferences.back();
1024
1025 if (params.useProgrammableSampleLocations)
1026 {
1027 const VkAttachmentSampleLocationsEXT newAttachmentSampleLocations =
1028 {
1029 attachmentReferences.back().attachment, // uint32_t attachmentIndex;
1030 perSubpassSampleLocationsInfo[subpassNdx], // VkSampleLocationsInfoEXT sampleLocationsInfo;
1031 };
1032 attachmentSampleLocations.push_back(newAttachmentSampleLocations);
1033
1034 const VkSubpassSampleLocationsEXT newSubpassSampleLocations =
1035 {
1036 subpassNdx, // uint32_t subpassIndex;
1037 perSubpassSampleLocationsInfo[subpassNdx], // VkSampleLocationsInfoEXT sampleLocationsInfo;
1038 };
1039 subpassSampleLocations.push_back(newSubpassSampleLocations);
1040 }
1041
1042 const VkSubpassDescription subpassDescription =
1043 {
1044 (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags;
1045 VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
1046 0u, // uint32_t inputAttachmentCount;
1047 DE_NULL, // const VkAttachmentReference* pInputAttachments;
1048 1u, // uint32_t colorAttachmentCount;
1049 colorRef, // const VkAttachmentReference* pColorAttachments;
1050 DE_NULL, // const VkAttachmentReference* pResolveAttachments;
1051 depthStencilRef, // const VkAttachmentReference* pDepthStencilAttachment;
1052 0u, // uint32_t preserveAttachmentCount;
1053 DE_NULL, // const uint32_t* pPreserveAttachments;
1054 };
1055
1056 subpasses.push_back(subpassDescription);
1057 }
1058
1059 // Assume there are no dependencies between subpasses
1060 const VkRenderPassCreateInfo renderPassInfo =
1061 {
1062 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
1063 DE_NULL, // const void* pNext;
1064 (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags;
1065 static_cast<deUint32>(attachmentDescriptions.size()), // deUint32 attachmentCount;
1066 dataOrNullPtr(attachmentDescriptions), // const VkAttachmentDescription* pAttachments;
1067 static_cast<deUint32>(subpasses.size()), // deUint32 subpassCount;
1068 dataOrNullPtr(subpasses), // const VkSubpassDescription* pSubpasses;
1069 0u, // deUint32 dependencyCount;
1070 DE_NULL, // const VkSubpassDependency* pDependencies;
1071 };
1072
1073 renderPass = createRenderPass(vk, device, &renderPassInfo);
1074 framebuffer = makeFramebuffer (vk, device, *renderPass, static_cast<deUint32>(attachments.size()), dataOrNullPtr(attachments), wd.renderSize.x(), wd.renderSize.y());
1075 }
1076
1077 const Unique<VkShaderModule> vertexModule (createShaderModule(vk, device, context.getBinaryCollection().get("vert"), 0u));
1078 const Unique<VkShaderModule> fragmentModule (createShaderModule(vk, device, context.getBinaryCollection().get("frag"), 0u));
1079 const Unique<VkPipelineLayout> pipelineLayout (makePipelineLayout(vk, device));
1080
1081 typedef SharedPtr<Unique<VkPipeline> > PipelineSp;
1082 std::vector<PipelineSp> pipelines;
1083
1084 for (deUint32 subpassNdx = 0; subpassNdx < numSubpasses; ++subpassNdx)
1085 {
1086 const VkSampleLocationsInfoEXT* pSampleLocationsInfo = (params.useProgrammableSampleLocations ? &perSubpassSampleLocationsInfo[subpassNdx] : DE_NULL);
1087
1088 pipelines.push_back(PipelineSp(new Unique<VkPipeline>(
1089 makeGraphicsPipeline(vk, device, *pipelineLayout, *renderPass, *vertexModule, *fragmentModule, /*use vertex input*/ true, subpassNdx,
1090 wd.renderSize, getImageAspectFlags(params.depthStencilFormat), params.perSubpassSamples[subpassNdx].numCoverageSamples,
1091 /*use sample shading*/ true, pSampleLocationsInfo))));
1092 }
1093
1094 const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, context.getUniversalQueueFamilyIndex()));
1095 const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer(vk, device, *cmdPool));
1096
1097 beginCommandBuffer(vk, *cmdBuffer);
1098
1099 {
1100 std::vector<VkClearValue> clearValues;
1101
1102 for (deUint32 subpassNdx = 0; subpassNdx < numSubpasses; ++subpassNdx)
1103 {
1104 clearValues.push_back(makeClearValueColorF32(0.0f, 0.0f, 0.0f, 1.0f));
1105 clearValues.push_back(makeClearValueDepthStencil(1.0f, 0u));
1106 }
1107
1108 const VkRect2D renderArea =
1109 {
1110 { 0u, 0u },
1111 { wd.renderSize.x(), wd.renderSize.y() }
1112 };
1113
1114 VkRenderPassBeginInfo renderPassBeginInfo =
1115 {
1116 VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType;
1117 DE_NULL, // const void* pNext;
1118 *renderPass, // VkRenderPass renderPass;
1119 *framebuffer, // VkFramebuffer framebuffer;
1120 renderArea, // VkRect2D renderArea;
1121 static_cast<deUint32>(clearValues.size()), // uint32_t clearValueCount;
1122 dataOrNullPtr(clearValues), // const VkClearValue* pClearValues;
1123 };
1124
1125 if (params.useProgrammableSampleLocations)
1126 {
1127 const VkRenderPassSampleLocationsBeginInfoEXT renderPassSampleLocationsBeginInfo =
1128 {
1129 VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT, // VkStructureType sType;
1130 DE_NULL, // const void* pNext;
1131 static_cast<deUint32>(attachmentSampleLocations.size()), // uint32_t attachmentInitialSampleLocationsCount;
1132 dataOrNullPtr(attachmentSampleLocations), // const VkAttachmentSampleLocationsEXT* pAttachmentInitialSampleLocations;
1133 static_cast<deUint32>(subpassSampleLocations.size()), // uint32_t postSubpassSampleLocationsCount;
1134 dataOrNullPtr(subpassSampleLocations), // const VkSubpassSampleLocationsEXT* pPostSubpassSampleLocations;
1135 };
1136
1137 renderPassBeginInfo.pNext = &renderPassSampleLocationsBeginInfo;
1138
1139 vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
1140 }
1141 else
1142 vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
1143 }
1144
1145 for (deUint32 subpassNdx = 0; subpassNdx < numSubpasses; ++subpassNdx)
1146 {
1147 if (subpassNdx != 0)
1148 vk.cmdNextSubpass(*cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
1149
1150 const VkDeviceSize vertexBufferOffset = 0ull;
1151 vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &wd.perSubpass[subpassNdx]->vertexBuffer.get(), &vertexBufferOffset);
1152
1153 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, **pipelines[subpassNdx]);
1154
1155 vk.cmdDraw(*cmdBuffer, wd.perSubpass[subpassNdx]->numVertices, 1u, 0u, 0u);
1156 }
1157
1158 vk.cmdEndRenderPass(*cmdBuffer);
1159
1160 VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
1161 submitCommandsAndWait(vk, device, context.getUniversalQueue(), *cmdBuffer);
1162 }
1163
dispatchImageCheck(Context & context,const TestParams & params,WorkingData & wd,const deUint32 subpassNdx)1164 void dispatchImageCheck (Context& context, const TestParams& params, WorkingData& wd, const deUint32 subpassNdx)
1165 {
1166 const DeviceInterface& vk = context.getDeviceInterface();
1167 const VkDevice device = context.getDevice();
1168 WorkingData::PerSubpass& subpassData = *wd.perSubpass[subpassNdx];
1169
1170 const Unique<VkSampler> defaultSampler (makeSampler(vk, device));
1171
1172 // Create descriptor set
1173
1174 const Unique<VkDescriptorSetLayout> descriptorSetLayout(
1175 DescriptorSetLayoutBuilder()
1176 .addSingleBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
1177 .addSingleBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
1178 .addSingleSamplerBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_COMPUTE_BIT, &defaultSampler.get())
1179 .addSingleSamplerBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_COMPUTE_BIT, &defaultSampler.get())
1180 .addSingleSamplerBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_COMPUTE_BIT, &defaultSampler.get())
1181 .build(vk, device));
1182
1183 const Unique<VkDescriptorPool> descriptorPool(
1184 DescriptorPoolBuilder()
1185 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2u)
1186 .addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 3u)
1187 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
1188
1189 const Unique<VkDescriptorSet> descriptorSet(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
1190
1191 {
1192 const VkDescriptorBufferInfo compareBufferInfo = makeDescriptorBufferInfo(*subpassData.compareBuffer, 0ull, subpassData.compareBufferSize);
1193 const VkDescriptorBufferInfo resultBufferInfo = makeDescriptorBufferInfo(*subpassData.resultBuffer, 0ull, subpassData.resultBufferSize);
1194 const VkDescriptorImageInfo colorImageInfo = makeDescriptorImageInfo(DE_NULL, *subpassData.colorImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
1195 const VkDescriptorImageInfo depthImageInfo = makeDescriptorImageInfo(DE_NULL, *subpassData.depthOnlyImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
1196 const VkDescriptorImageInfo stencilImageInfo = makeDescriptorImageInfo(DE_NULL, *subpassData.stencilOnlyImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
1197
1198 DescriptorSetUpdateBuilder builder;
1199
1200 builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultBufferInfo);
1201 builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &compareBufferInfo);
1202 builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(2u), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &colorImageInfo);
1203
1204 if (subpassData.depthOnlyImageView)
1205 builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(3u), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &depthImageInfo);
1206
1207 if (subpassData.stencilOnlyImageView)
1208 builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(4u), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &stencilImageInfo);
1209
1210 builder.update(vk, device);
1211 }
1212
1213 // Pipeline
1214
1215 const std::string shaderName ("comp_" + getSampleCountString(params.perSubpassSamples[subpassNdx]));
1216 const Unique<VkShaderModule> shaderModule (createShaderModule(vk, device, context.getBinaryCollection().get(shaderName), 0u));
1217 const Unique<VkPipelineLayout> pipelineLayout (makePipelineLayout(vk, device, *descriptorSetLayout));
1218 const Unique<VkPipeline> pipeline (makeComputePipeline(vk, device, *pipelineLayout, *shaderModule, DE_NULL));
1219
1220 const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, context.getUniversalQueueFamilyIndex()));
1221 const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer(vk, device, *cmdPool));
1222
1223 beginCommandBuffer(vk, *cmdBuffer);
1224
1225 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
1226 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
1227
1228 vk.cmdDispatch(*cmdBuffer, wd.renderSize.x(), wd.renderSize.y(), 1u);
1229
1230 {
1231 const VkBufferMemoryBarrier barrier =
1232 {
1233 VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType;
1234 DE_NULL, // const void* pNext;
1235 VK_ACCESS_SHADER_WRITE_BIT, // VkAccessFlags srcAccessMask;
1236 VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask;
1237 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
1238 VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex;
1239 *subpassData.resultBuffer, // VkBuffer buffer;
1240 0ull, // VkDeviceSize offset;
1241 VK_WHOLE_SIZE, // VkDeviceSize size;
1242 };
1243
1244 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 0,
1245 (const VkMemoryBarrier*)DE_NULL, 1u, &barrier, 0u, (const VkImageMemoryBarrier*)DE_NULL);
1246 }
1247
1248 VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
1249 submitCommandsAndWait(vk, device, context.getUniversalQueue(), *cmdBuffer);
1250
1251 invalidateMappedMemoryRange(vk, device, subpassData.resultBufferAlloc->getMemory(), subpassData.resultBufferAlloc->getOffset(), VK_WHOLE_SIZE);
1252 }
1253
createPerSubpassData(Context & context,const TestParams & params,WorkingData & wd,const deUint32 subpassNdx)1254 void createPerSubpassData (Context& context, const TestParams& params, WorkingData& wd, const deUint32 subpassNdx)
1255 {
1256 const DeviceInterface& vk = context.getDeviceInterface();
1257 const VkDevice device = context.getDevice();
1258 MovePtr<Allocator> allocator = MovePtr<Allocator>(new SimpleAllocator(vk, device, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice())));
1259 const TestParams::SampleCount& samples = params.perSubpassSamples[subpassNdx];
1260 WorkingData::PerSubpass& subpassData = *wd.perSubpass[subpassNdx];
1261
1262 // Create images
1263 {
1264
1265 const VkImageUsageFlags colorImageUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
1266 const VkImageUsageFlags depthStencilImageUsageFlags = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
1267
1268 checkImageRequirements (context,
1269 params.colorFormat,
1270 VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT,
1271 colorImageUsageFlags,
1272 samples.numColorSamples);
1273
1274 subpassData.colorImage = makeImage(vk, device, params.colorFormat, wd.renderSize, samples.numColorSamples, colorImageUsageFlags);
1275 subpassData.colorImageAlloc = bindImage(vk, device, *allocator, *subpassData.colorImage, MemoryRequirement::Any);
1276 subpassData.colorImageView = makeImageView(vk, device, *subpassData.colorImage, VK_IMAGE_VIEW_TYPE_2D, params.colorFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
1277
1278 checkImageRequirements (context,
1279 params.depthStencilFormat,
1280 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT,
1281 depthStencilImageUsageFlags,
1282 samples.numDepthStencilSamples);
1283
1284 subpassData.depthStencilImage = makeImage(vk, device, params.depthStencilFormat, wd.renderSize, samples.numDepthStencilSamples, depthStencilImageUsageFlags);
1285 subpassData.depthStencilImageAlloc = bindImage(vk, device, *allocator, *subpassData.depthStencilImage, MemoryRequirement::Any);
1286 subpassData.depthStencilImageView = makeImageView(vk, device, *subpassData.depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, params.depthStencilFormat, makeImageSubresourceRange(getImageAspectFlags(params.depthStencilFormat), 0u, 1u, 0u, 1u));
1287
1288 if (isDepthFormat(params.depthStencilFormat))
1289 subpassData.depthOnlyImageView = makeImageView(vk, device, *subpassData.depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, params.depthStencilFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 1u, 0u, 1u));
1290
1291 if (isStencilFormat(params.depthStencilFormat))
1292 subpassData.stencilOnlyImageView = makeImageView(vk, device, *subpassData.depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, params.depthStencilFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_STENCIL_BIT, 0u, 1u, 0u, 1u));
1293 }
1294
1295 // Create vertex and comparison buffers
1296 {
1297 const deUint32 seed = 123 + 19 * subpassNdx;
1298 const std::vector<CompareData> compareData = generateCompareData(seed, wd.renderSize, samples.numCoverageSamples, samples.numColorSamples, samples.numDepthStencilSamples);
1299
1300 subpassData.compareBufferSize = static_cast<VkDeviceSize>(sizeof(CompareData) * compareData.size());
1301 subpassData.compareBuffer = makeBuffer(vk, device, subpassData.compareBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
1302 subpassData.compareBufferAlloc = bindBuffer(vk, device, *allocator, *subpassData.compareBuffer, MemoryRequirement::HostVisible);
1303
1304 deMemcpy(subpassData.compareBufferAlloc->getHostPtr(), dataOrNullPtr(compareData), static_cast<std::size_t>(subpassData.compareBufferSize));
1305 flushMappedMemoryRange(vk, device, subpassData.compareBufferAlloc->getMemory(), subpassData.compareBufferAlloc->getOffset(), VK_WHOLE_SIZE);
1306
1307 subpassData.numResultElements = static_cast<deUint32>(compareData.size());
1308 subpassData.resultBufferSize = static_cast<VkDeviceSize>(sizeof(deUint32) * compareData.size());
1309 subpassData.resultBuffer = makeBuffer(vk, device, subpassData.resultBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
1310 subpassData.resultBufferAlloc = bindBuffer(vk, device, *allocator, *subpassData.resultBuffer, MemoryRequirement::HostVisible);
1311
1312 deMemset(subpassData.resultBufferAlloc->getHostPtr(), 0, static_cast<std::size_t>(subpassData.resultBufferSize));
1313 flushMappedMemoryRange(vk, device, subpassData.resultBufferAlloc->getMemory(), subpassData.resultBufferAlloc->getOffset(), VK_WHOLE_SIZE);
1314
1315 std::vector<PositionColor> vertices;
1316
1317 if (params.useProgrammableSampleLocations)
1318 {
1319 subpassData.pixelGrid = MovePtr<MultisamplePixelGrid>(new MultisamplePixelGrid(UVec2(wd.sampleLocationsProperties.maxSampleLocationGridSize.width,
1320 wd.sampleLocationsProperties.maxSampleLocationGridSize.height),
1321 samples.numCoverageSamples));
1322
1323 const deUint32 locationsSeed = 211 + 4 * subpassNdx;
1324 fillSampleLocationsRandom(*subpassData.pixelGrid, wd.sampleLocationsProperties.sampleLocationSubPixelBits, locationsSeed);
1325 vertices = generateSubpixelTriangles(wd.renderSize, compareData, getSampleLocations(*subpassData.pixelGrid, wd.renderSize));
1326 }
1327 else
1328 {
1329 const std::vector<Vec2> locations = genFramebufferStandardSampleLocations(samples.numCoverageSamples, wd.renderSize);
1330 vertices = generateSubpixelTriangles(wd.renderSize, compareData, locations);
1331 }
1332
1333 const VkDeviceSize vertexBufferSize = static_cast<VkDeviceSize>(sizeof(vertices[0]) * vertices.size());
1334 subpassData.numVertices = static_cast<deUint32>(vertices.size());
1335 subpassData.vertexBuffer = makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
1336 subpassData.vertexBufferAlloc = bindBuffer(vk, device, *allocator, *subpassData.vertexBuffer, MemoryRequirement::HostVisible);
1337
1338 deMemcpy(subpassData.vertexBufferAlloc->getHostPtr(), dataOrNullPtr(vertices), static_cast<std::size_t>(vertexBufferSize));
1339 flushMappedMemoryRange(vk, device, subpassData.vertexBufferAlloc->getMemory(), subpassData.vertexBufferAlloc->getOffset(), VK_WHOLE_SIZE);
1340 }
1341 }
1342
checkRequirements(Context & context,TestParams params)1343 void checkRequirements (Context& context, TestParams params)
1344 {
1345 context.requireDeviceFunctionality("VK_AMD_mixed_attachment_samples");
1346
1347 if (params.useProgrammableSampleLocations)
1348 context.requireDeviceFunctionality("VK_EXT_sample_locations");
1349
1350 for (deUint32 subpassNdx = 0; subpassNdx < static_cast<deUint32>(params.perSubpassSamples.size()); ++subpassNdx)
1351 {
1352 const TestParams::SampleCount& samples = params.perSubpassSamples[subpassNdx];
1353 checkSampleRequirements(context, samples.numColorSamples, samples.numDepthStencilSamples, !params.useProgrammableSampleLocations);
1354 }
1355 }
1356
1357 //! Verify the values of all samples in all attachments.
test(Context & context,const TestParams params)1358 tcu::TestStatus test (Context& context, const TestParams params)
1359 {
1360 WorkingData wd;
1361 wd.renderSize = UVec2(2, 2); // Use a very small image, as we will verify all samples for all pixels
1362
1363 // Query state related to programmable sample locations
1364 if (params.useProgrammableSampleLocations)
1365 {
1366 const InstanceInterface& vki = context.getInstanceInterface();
1367 const VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
1368
1369 wd.sampleLocationsProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT;
1370 wd.sampleLocationsProperties.pNext = DE_NULL;
1371
1372 VkPhysicalDeviceProperties2 properties =
1373 {
1374 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR, // VkStructureType sType;
1375 &wd.sampleLocationsProperties, // void* pNext;
1376 VkPhysicalDeviceProperties(), // VkPhysicalDeviceProperties properties;
1377 };
1378
1379 vki.getPhysicalDeviceProperties2(physicalDevice, &properties);
1380
1381 for (deUint32 subpassNdx = 0; subpassNdx < static_cast<deUint32>(params.perSubpassSamples.size()); ++subpassNdx)
1382 {
1383 if ((wd.sampleLocationsProperties.sampleLocationSampleCounts & params.perSubpassSamples[subpassNdx].numCoverageSamples) == 0u)
1384 TCU_THROW(NotSupportedError, "VkSampleLocationsPropertiesAMD: sample count not supported");
1385 }
1386 }
1387
1388 // Create subpass data
1389 for (deUint32 subpassNdx = 0; subpassNdx < static_cast<deUint32>(params.perSubpassSamples.size()); ++subpassNdx)
1390 {
1391 wd.perSubpass.push_back(SharedPtr<WorkingData::PerSubpass>(new WorkingData::PerSubpass()));
1392 createPerSubpassData(context, params, wd, subpassNdx);
1393 }
1394
1395 // Draw test geometry
1396 draw (context, params, wd);
1397
1398 // Verify images with a compute shader
1399 for (deUint32 subpassNdx = 0; subpassNdx < static_cast<deUint32>(params.perSubpassSamples.size()); ++subpassNdx)
1400 dispatchImageCheck (context, params, wd, subpassNdx);
1401
1402 // Test checksums
1403 for (deUint32 subpassNdx = 0; subpassNdx < static_cast<deUint32>(params.perSubpassSamples.size()); ++subpassNdx)
1404 {
1405 const deUint32* const pSampleChecksumBase = static_cast<deUint32*>(wd.perSubpass[subpassNdx]->resultBufferAlloc->getHostPtr());
1406 const bool hasDepth = isDepthFormat(params.depthStencilFormat);
1407 const bool hasStencil = isStencilFormat(params.depthStencilFormat);
1408 bool allOk = true;
1409
1410 context.getTestContext().getLog() << tcu::TestLog::Message << "Verify images in subpass " << subpassNdx << tcu::TestLog::EndMessage;
1411
1412 for (deUint32 globalSampleNdx = 0; globalSampleNdx < wd.perSubpass[subpassNdx]->numResultElements; ++globalSampleNdx)
1413 {
1414 const TestParams::SampleCount& samples = params.perSubpassSamples[subpassNdx];
1415 const deUint32 checksum = pSampleChecksumBase[globalSampleNdx];
1416
1417 if ((checksum & VK_IMAGE_ASPECT_COLOR_BIT) == 0u)
1418 {
1419 reportSampleError(context.getTestContext().getLog(), "color", wd.renderSize, samples.numCoverageSamples, globalSampleNdx);
1420 allOk = false;
1421 }
1422
1423 if (hasDepth && ((checksum & VK_IMAGE_ASPECT_DEPTH_BIT) == 0u))
1424 {
1425 reportSampleError(context.getTestContext().getLog(), "depth", wd.renderSize, samples.numCoverageSamples, globalSampleNdx);
1426 allOk = false;
1427 }
1428
1429 if (hasStencil && ((checksum & VK_IMAGE_ASPECT_STENCIL_BIT) == 0u))
1430 {
1431 reportSampleError(context.getTestContext().getLog(), "stencil", wd.renderSize, samples.numCoverageSamples, globalSampleNdx);
1432 allOk = false;
1433 }
1434 }
1435
1436 if (!allOk)
1437 return tcu::TestStatus::fail("Multisampled image has incorrect samples");
1438 }
1439
1440 return tcu::TestStatus::pass("Pass");
1441 }
1442
1443 } // VerifySamples
1444
1445 namespace ShaderBuiltins
1446 {
1447
1448 struct TestParams
1449 {
1450 VkSampleCountFlagBits numCoverageSamples; //!< VkPipelineMultisampleStateCreateInfo::rasterizationSamples
1451 VkSampleCountFlagBits numColorSamples; //!< VkAttachmentDescription::samples and VkImageCreateInfo::samples
1452 VkSampleCountFlagBits numDepthStencilSamples; //!< VkAttachmentDescription::samples and VkImageCreateInfo::samples
1453 VkFormat colorFormat; //!< Color attachment format
1454 VkFormat depthStencilFormat; //!< D/S attachment format. Will test both aspects if it's a mixed format
1455 };
1456
1457 struct WorkingData
1458 {
1459 UVec2 renderSize; //!< Size of the framebuffer
1460 deUint32 numVertices; //!< Number of vertices defined in the vertex buffer
1461 Move<VkBuffer> vertexBuffer;
1462 MovePtr<Allocation> vertexBufferAlloc;
1463 Move<VkImage> colorImage; //!< Color image
1464 Move<VkImageView> colorImageView; //!< Color attachment
1465 MovePtr<Allocation> colorImageAlloc;
1466 Move<VkImage> depthStencilImage; //!< Depth stencil image
1467 Move<VkImageView> depthStencilImageView; //!< Depth stencil attachment
1468 Move<VkImageView> depthOnlyImageView; //!< Depth aspect for shader read
1469 Move<VkImageView> stencilOnlyImageView; //!< Stencil aspect for shader read
1470 MovePtr<Allocation> depthStencilImageAlloc;
1471 Move<VkImage> resolveImage; //!< Resolve image
1472 Move<VkImageView> resolveImageView; //!< Resolve attachment
1473 MovePtr<Allocation> resolveImageAlloc;
1474 Move<VkBuffer> colorBuffer; //!< Buffer used to copy resolve output
1475 MovePtr<Allocation> colorBufferAlloc;
1476 VkDeviceSize colorBufferSize;
1477
WorkingDatavkt::pipeline::__anonc89cd22b0111::ShaderBuiltins::WorkingData1478 WorkingData (void)
1479 : numVertices ()
1480 {
1481 }
1482 };
1483
initPrograms(SourceCollections & programCollection,const TestParams params)1484 void initPrograms (SourceCollections& programCollection, const TestParams params)
1485 {
1486 // Vertex shader - no vertex data
1487 {
1488 std::ostringstream src;
1489 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1490 << "\n"
1491 << "out gl_PerVertex {\n"
1492 << " vec4 gl_Position;\n"
1493 << "};\n"
1494 << "\n"
1495 << "void main(void)\n"
1496 << "{\n"
1497 // Specify an oversized triangle covering the whole viewport.
1498 << " switch (gl_VertexIndex)\n"
1499 << " {\n"
1500 << " case 0:\n"
1501 << " gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
1502 << " break;\n"
1503 << " case 1:\n"
1504 << " gl_Position = vec4(-1.0, 3.0, 0.0, 1.0);\n"
1505 << " break;\n"
1506 << " case 2:\n"
1507 << " gl_Position = vec4( 3.0, -1.0, 0.0, 1.0);\n"
1508 << " break;\n"
1509 << " }\n"
1510 << "}\n";
1511
1512 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
1513 }
1514
1515 // Fragment shader
1516 {
1517 std::ostringstream src;
1518 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1519 << "\n"
1520 << "layout(location = 0) out vec4 o_color;\n"
1521 << "\n"
1522 << "void main(void)\n"
1523 << "{\n"
1524 << " vec4 col = vec4(0.0, 0.0, 0.0, 1.0);\n"
1525 << "\n";
1526
1527 if (params.numColorSamples == VK_SAMPLE_COUNT_1_BIT)
1528 {
1529 const deUint32 expectedMask = ((1u << static_cast<deUint32>(params.numCoverageSamples)) - 1u);
1530
1531 // Expect all covered samples to be lit, the rest is zero
1532 src << " if (gl_SampleMaskIn[0] == " << expectedMask << ")\n"
1533 << " col.g = 1.0;\n"
1534 << " else\n"
1535 << " col.r = 1.0;\n";
1536 }
1537 else
1538 {
1539 // Expect only a matching sample to be lit
1540 src << " if (gl_SampleMaskIn[0] == (1 << gl_SampleID))\n"
1541 << " col.g = 1.0;\n"
1542 << " else\n"
1543 << " col.r = 1.0;\n"
1544 << "\n"
1545 << " if (gl_SampleID >= " << static_cast<deUint32>(params.numColorSamples) << ") // number of color samples, should not happen\n"
1546 << " col.b = 1.0;\n";
1547 }
1548
1549 src << "\n"
1550 << " o_color = col;\n"
1551 << "}\n";
1552
1553 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
1554 }
1555 }
1556
1557 //! A simple color, depth/stencil draw. Single subpass, no vertex input
drawResolve(Context & context,const TestParams & params,WorkingData & wd)1558 void drawResolve (Context& context, const TestParams& params, WorkingData& wd)
1559 {
1560 const DeviceInterface& vk = context.getDeviceInterface();
1561 const VkDevice device = context.getDevice();
1562 const bool needResolve = (params.numColorSamples != VK_SAMPLE_COUNT_1_BIT);
1563
1564 Move<VkRenderPass> renderPass;
1565 Move<VkFramebuffer> framebuffer;
1566
1567 // Create a render pass and a framebuffer
1568 {
1569 std::vector<VkImageView> attachments;
1570 std::vector<VkAttachmentDescription> attachmentDescriptions;
1571
1572 attachments.push_back(*wd.colorImageView);
1573 attachments.push_back(*wd.depthStencilImageView);
1574
1575 attachmentDescriptions.push_back(makeAttachmentDescription(
1576 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags;
1577 params.colorFormat, // VkFormat format;
1578 params.numColorSamples, // VkSampleCountFlagBits samples;
1579 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
1580 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
1581 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
1582 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
1583 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
1584 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL // VkImageLayout finalLayout;
1585 ));
1586
1587 attachmentDescriptions.push_back(makeAttachmentDescription(
1588 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags;
1589 params.depthStencilFormat, // VkFormat format;
1590 params.numDepthStencilSamples, // VkSampleCountFlagBits samples;
1591 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
1592 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
1593 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp stencilLoadOp;
1594 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp stencilStoreOp;
1595 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
1596 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout;
1597 ));
1598
1599 if (needResolve)
1600 {
1601 attachments.push_back(*wd.resolveImageView);
1602
1603 attachmentDescriptions.push_back(makeAttachmentDescription(
1604 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags;
1605 params.colorFormat, // VkFormat format;
1606 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
1607 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp loadOp;
1608 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
1609 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
1610 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
1611 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
1612 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL // VkImageLayout finalLayout;
1613 ));
1614 }
1615
1616 const VkAttachmentReference colorRef = makeAttachmentReference(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
1617 const VkAttachmentReference depthStencilRef = makeAttachmentReference(1u, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
1618 const VkAttachmentReference resolveRef = makeAttachmentReference(2u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
1619
1620 const VkSubpassDescription subpassDescription =
1621 {
1622 (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags;
1623 VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
1624 0u, // uint32_t inputAttachmentCount;
1625 DE_NULL, // const VkAttachmentReference* pInputAttachments;
1626 1u, // uint32_t colorAttachmentCount;
1627 &colorRef, // const VkAttachmentReference* pColorAttachments;
1628 (needResolve ? &resolveRef : DE_NULL), // const VkAttachmentReference* pResolveAttachments;
1629 &depthStencilRef, // const VkAttachmentReference* pDepthStencilAttachment;
1630 0u, // uint32_t preserveAttachmentCount;
1631 DE_NULL, // const uint32_t* pPreserveAttachments;
1632 };
1633
1634 // Assume there are no dependencies between subpasses
1635 VkRenderPassCreateInfo renderPassInfo =
1636 {
1637 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
1638 DE_NULL, // const void* pNext;
1639 (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags;
1640 static_cast<deUint32>(attachmentDescriptions.size()), // deUint32 attachmentCount;
1641 dataOrNullPtr(attachmentDescriptions), // const VkAttachmentDescription* pAttachments;
1642 1u, // deUint32 subpassCount;
1643 &subpassDescription, // const VkSubpassDescription* pSubpasses;
1644 0u, // deUint32 dependencyCount;
1645 DE_NULL, // const VkSubpassDependency* pDependencies;
1646 };
1647
1648 renderPass = createRenderPass(vk, device, &renderPassInfo);
1649 framebuffer = makeFramebuffer (vk, device, *renderPass, static_cast<deUint32>(attachments.size()), dataOrNullPtr(attachments), wd.renderSize.x(), wd.renderSize.y());
1650 }
1651
1652 const Unique<VkShaderModule> vertexModule (createShaderModule(vk, device, context.getBinaryCollection().get("vert"), 0u));
1653 const Unique<VkShaderModule> fragmentModule (createShaderModule(vk, device, context.getBinaryCollection().get("frag"), 0u));
1654 const Unique<VkPipelineLayout> pipelineLayout (makePipelineLayout(vk, device));
1655 const bool useVertexInput = false;
1656 const bool sampleShading = (params.numColorSamples != VK_SAMPLE_COUNT_1_BIT);
1657 const deUint32 subpassNdx = 0u;
1658 const Unique<VkPipeline> pipeline (makeGraphicsPipeline(vk, device, *pipelineLayout, *renderPass, *vertexModule, *fragmentModule, useVertexInput, subpassNdx,
1659 wd.renderSize, getImageAspectFlags(params.depthStencilFormat), params.numCoverageSamples, sampleShading));
1660
1661 const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, context.getUniversalQueueFamilyIndex()));
1662 const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer(vk, device, *cmdPool));
1663
1664 beginCommandBuffer(vk, *cmdBuffer);
1665
1666 {
1667 std::vector<VkClearValue> clearValues;
1668 clearValues.push_back(makeClearValueColorF32(0.0f, 0.0f, 0.0f, 1.0f));
1669 clearValues.push_back(makeClearValueDepthStencil(1.0f, 0u));
1670
1671 const VkRect2D renderArea =
1672 {
1673 { 0u, 0u },
1674 { wd.renderSize.x(), wd.renderSize.y() }
1675 };
1676
1677 const VkRenderPassBeginInfo renderPassBeginInfo =
1678 {
1679 VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType;
1680 DE_NULL, // const void* pNext;
1681 *renderPass, // VkRenderPass renderPass;
1682 *framebuffer, // VkFramebuffer framebuffer;
1683 renderArea, // VkRect2D renderArea;
1684 static_cast<deUint32>(clearValues.size()), // uint32_t clearValueCount;
1685 dataOrNullPtr(clearValues), // const VkClearValue* pClearValues;
1686 };
1687 vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
1688 }
1689
1690 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
1691 vk.cmdDraw(*cmdBuffer, 3u, 1u, 0u, 0u);
1692
1693 vk.cmdEndRenderPass(*cmdBuffer);
1694
1695 if (needResolve)
1696 recordCopyOutputImageToBuffer(vk, *cmdBuffer, wd.renderSize, *wd.resolveImage, *wd.colorBuffer);
1697 else
1698 recordCopyOutputImageToBuffer(vk, *cmdBuffer, wd.renderSize, *wd.colorImage, *wd.colorBuffer);
1699
1700 VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
1701 submitCommandsAndWait(vk, device, context.getUniversalQueue(), *cmdBuffer);
1702 }
1703
checkRequirements(Context & context,TestParams params)1704 void checkRequirements (Context& context, TestParams params)
1705 {
1706 context.requireDeviceFunctionality("VK_AMD_mixed_attachment_samples");
1707
1708 checkSampleRequirements(context, params.numColorSamples, params.numDepthStencilSamples, false /* require standard sample locations */);
1709 }
1710
1711 //! Verify the values of shader builtins
test(Context & context,const TestParams params)1712 tcu::TestStatus test (Context& context, const TestParams params)
1713 {
1714 WorkingData wd;
1715 const DeviceInterface& vk = context.getDeviceInterface();
1716 const VkDevice device = context.getDevice();
1717 MovePtr<Allocator> allocator = MovePtr<Allocator>(new SimpleAllocator(vk, device, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice())));
1718
1719 wd.renderSize = UVec2(16, 16);
1720
1721 // Create images and a color buffer
1722 {
1723
1724 const VkImageUsageFlags colorImageUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
1725 const VkImageUsageFlags depthStencilImageUsageFlags = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
1726
1727 checkImageRequirements (context,
1728 params.colorFormat,
1729 VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT,
1730 colorImageUsageFlags,
1731 params.numColorSamples);
1732
1733 wd.colorImage = makeImage(vk, device, params.colorFormat, wd.renderSize, params.numColorSamples, colorImageUsageFlags);
1734 wd.colorImageAlloc = bindImage(vk, device, *allocator, *wd.colorImage, MemoryRequirement::Any);
1735 wd.colorImageView = makeImageView(vk, device, *wd.colorImage, VK_IMAGE_VIEW_TYPE_2D, params.colorFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
1736
1737 if (params.numColorSamples != VK_SAMPLE_COUNT_1_BIT)
1738 {
1739 wd.resolveImage = makeImage(vk, device, params.colorFormat, wd.renderSize, VK_SAMPLE_COUNT_1_BIT, colorImageUsageFlags);
1740 wd.resolveImageAlloc = bindImage(vk, device, *allocator, *wd.resolveImage, MemoryRequirement::Any);
1741 wd.resolveImageView = makeImageView(vk, device, *wd.resolveImage, VK_IMAGE_VIEW_TYPE_2D, params.colorFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
1742 }
1743
1744 // Resolve result
1745 wd.colorBufferSize = static_cast<VkDeviceSize>(tcu::getPixelSize(mapVkFormat(params.colorFormat)) * wd.renderSize.x() * wd.renderSize.y());
1746 wd.colorBuffer = makeBuffer(vk, device, wd.colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
1747 wd.colorBufferAlloc = bindBuffer(vk, device, *allocator, *wd.colorBuffer, MemoryRequirement::HostVisible);
1748
1749 deMemset(wd.colorBufferAlloc->getHostPtr(), 0, static_cast<std::size_t>(wd.colorBufferSize));
1750 flushMappedMemoryRange(vk, device, wd.colorBufferAlloc->getMemory(), wd.colorBufferAlloc->getOffset(), VK_WHOLE_SIZE);
1751
1752 checkImageRequirements (context,
1753 params.depthStencilFormat,
1754 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT,
1755 depthStencilImageUsageFlags,
1756 params.numDepthStencilSamples);
1757
1758 wd.depthStencilImage = makeImage(vk, device, params.depthStencilFormat, wd.renderSize, params.numDepthStencilSamples, depthStencilImageUsageFlags);
1759 wd.depthStencilImageAlloc = bindImage(vk, device, *allocator, *wd.depthStencilImage, MemoryRequirement::Any);
1760 wd.depthStencilImageView = makeImageView(vk, device, *wd.depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, params.depthStencilFormat, makeImageSubresourceRange(getImageAspectFlags(params.depthStencilFormat), 0u, 1u, 0u, 1u));
1761
1762 if (isDepthFormat(params.depthStencilFormat))
1763 wd.depthOnlyImageView = makeImageView(vk, device, *wd.depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, params.depthStencilFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 1u, 0u, 1u));
1764
1765 if (isStencilFormat(params.depthStencilFormat))
1766 wd.stencilOnlyImageView = makeImageView(vk, device, *wd.depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, params.depthStencilFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_STENCIL_BIT, 0u, 1u, 0u, 1u));
1767 }
1768
1769 // Draw, resolve, and copy to color buffer (see the fragment shader for details)
1770 drawResolve(context, params, wd);
1771
1772 // Verify resolved image
1773 {
1774 const tcu::ConstPixelBufferAccess image (tcu::ConstPixelBufferAccess(mapVkFormat(params.colorFormat), tcu::IVec3(wd.renderSize.x(), wd.renderSize.y(), 1),wd.colorBufferAlloc->getHostPtr()));
1775
1776 if (compareGreenImage(context.getTestContext().getLog(), "resolve0", "Resolved test image", image))
1777 return tcu::TestStatus::pass("Pass");
1778 else
1779 return tcu::TestStatus::fail("Some samples were incorrect");
1780 }
1781 }
1782
1783 } // ShaderBuiltins
1784
getSampleCountGroupName(const VkSampleCountFlagBits coverageCount,const VkSampleCountFlagBits colorCount,const VkSampleCountFlagBits depthStencilCount)1785 std::string getSampleCountGroupName(const VkSampleCountFlagBits coverageCount,
1786 const VkSampleCountFlagBits colorCount,
1787 const VkSampleCountFlagBits depthStencilCount)
1788 {
1789 std::ostringstream str;
1790 str << "coverage_" << static_cast<deUint32>(coverageCount)
1791 << "_color_" << static_cast<deUint32>(colorCount)
1792 << "_depth_stencil_" << static_cast<deUint32>(depthStencilCount);
1793 return str.str();
1794 }
1795
getFormatShortString(const VkFormat format)1796 std::string getFormatShortString (const VkFormat format)
1797 {
1798 std::string s(de::toLower(getFormatName(format)));
1799 return s.substr(10);
1800 }
1801
getFormatCaseName(const VkFormat colorFormat,const VkFormat depthStencilFormat)1802 std::string getFormatCaseName (const VkFormat colorFormat,
1803 const VkFormat depthStencilFormat)
1804 {
1805 std::ostringstream str;
1806 str << getFormatShortString(colorFormat) << "_" << getFormatShortString(depthStencilFormat);
1807 return str.str();
1808 }
1809
createMixedAttachmentSamplesTestsInGroup(tcu::TestCaseGroup * rootGroup)1810 void createMixedAttachmentSamplesTestsInGroup (tcu::TestCaseGroup* rootGroup)
1811 {
1812 const VkFormat colorFormatRange[] =
1813 {
1814 VK_FORMAT_R8G8B8A8_UNORM,
1815 // If you add more, make sure it is handled in the test/shader
1816 };
1817
1818 const VkFormat depthStencilFormatRange[] =
1819 {
1820 VK_FORMAT_D16_UNORM,
1821 VK_FORMAT_X8_D24_UNORM_PACK32,
1822 VK_FORMAT_D32_SFLOAT,
1823 VK_FORMAT_S8_UINT,
1824 VK_FORMAT_D16_UNORM_S8_UINT,
1825 VK_FORMAT_D24_UNORM_S8_UINT,
1826 VK_FORMAT_D32_SFLOAT_S8_UINT,
1827 };
1828
1829 // Minimal set of formats to cover depth and stencil
1830 const VkFormat depthStencilReducedFormatRange[] =
1831 {
1832 VK_FORMAT_D16_UNORM, //!< Must be supported
1833 VK_FORMAT_D24_UNORM_S8_UINT, //!< Either this, or the next one must be supported
1834 VK_FORMAT_D32_SFLOAT_S8_UINT,
1835 };
1836
1837 struct SampleCase
1838 {
1839 VkSampleCountFlagBits colorSamples;
1840 VkSampleCountFlagBits depthStencilSamples;
1841 };
1842
1843 // Currently supported EQAA cases
1844 static const SampleCase singlePassCases[] =
1845 {
1846 // Less color than depth/stencil
1847 { VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_2_BIT },
1848 { VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_4_BIT },
1849 { VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_8_BIT },
1850 { VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_16_BIT },
1851 { VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_4_BIT },
1852 { VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_8_BIT },
1853 { VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_16_BIT },
1854 { VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_8_BIT },
1855 { VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_16_BIT },
1856 { VK_SAMPLE_COUNT_8_BIT, VK_SAMPLE_COUNT_16_BIT },
1857 };
1858
1859 // Multi-subpass cases
1860
1861 static const SampleCase caseSubpassIncreaseColor_1[] =
1862 {
1863 { VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_4_BIT },
1864 { VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_4_BIT },
1865 };
1866 static const SampleCase caseSubpassIncreaseColor_2[] =
1867 {
1868 { VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_8_BIT },
1869 { VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_8_BIT },
1870 { VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_8_BIT },
1871 };
1872 static const SampleCase caseSubpassDecreaseColor_1[] =
1873 {
1874 { VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_4_BIT },
1875 { VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_4_BIT },
1876 };
1877 static const SampleCase caseSubpassDecreaseColor_2[] =
1878 {
1879 { VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_8_BIT },
1880 { VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_8_BIT },
1881 { VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_8_BIT },
1882 };
1883 static const SampleCase caseSubpassIncreaseCoverage_1[] =
1884 {
1885 { VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_2_BIT },
1886 { VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_4_BIT },
1887 };
1888 static const SampleCase caseSubpassIncreaseCoverage_2[] =
1889 {
1890 { VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_2_BIT },
1891 { VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_4_BIT },
1892 { VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_8_BIT },
1893 };
1894 static const SampleCase caseSubpassDecreaseCoverage_1[] =
1895 {
1896 { VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_4_BIT },
1897 { VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_2_BIT },
1898 };
1899 static const SampleCase caseSubpassDecreaseCoverage_2[] =
1900 {
1901 { VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_8_BIT },
1902 { VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_4_BIT },
1903 { VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_2_BIT },
1904 };
1905
1906 static const struct
1907 {
1908 const char* const caseName;
1909 const deUint32 numSampleCases;
1910 const SampleCase* pSampleCase;
1911 } subpassCases[] =
1912 {
1913 { "multi_subpass_decrease_color_4", DE_LENGTH_OF_ARRAY(caseSubpassDecreaseColor_1), caseSubpassDecreaseColor_1 },
1914 { "multi_subpass_decrease_color_8", DE_LENGTH_OF_ARRAY(caseSubpassDecreaseColor_2), caseSubpassDecreaseColor_2 },
1915 { "multi_subpass_decrease_coverage_4", DE_LENGTH_OF_ARRAY(caseSubpassDecreaseCoverage_1), caseSubpassDecreaseCoverage_1 },
1916 { "multi_subpass_decrease_coverage_8", DE_LENGTH_OF_ARRAY(caseSubpassDecreaseCoverage_2), caseSubpassDecreaseCoverage_2 },
1917 { "multi_subpass_increase_color_4", DE_LENGTH_OF_ARRAY(caseSubpassIncreaseColor_1), caseSubpassIncreaseColor_1 },
1918 { "multi_subpass_increase_color_8", DE_LENGTH_OF_ARRAY(caseSubpassIncreaseColor_2), caseSubpassIncreaseColor_2 },
1919 { "multi_subpass_increase_coverage_4", DE_LENGTH_OF_ARRAY(caseSubpassIncreaseCoverage_1), caseSubpassIncreaseCoverage_1 },
1920 { "multi_subpass_increase_coverage_8", DE_LENGTH_OF_ARRAY(caseSubpassIncreaseCoverage_2), caseSubpassIncreaseCoverage_2 },
1921 };
1922
1923 // Test 1: Per-sample expected value check
1924 {
1925 MovePtr<tcu::TestCaseGroup> standardLocationsGroup (new tcu::TestCaseGroup(rootGroup->getTestContext(), "verify_standard_locations", ""));
1926 MovePtr<tcu::TestCaseGroup> programmableLocationsGroup (new tcu::TestCaseGroup(rootGroup->getTestContext(), "verify_programmable_locations", ""));
1927
1928 tcu::TestCaseGroup* locationsGroups[2] =
1929 {
1930 standardLocationsGroup.get(),
1931 programmableLocationsGroup.get()
1932 };
1933
1934 for (deUint32 groupNdx = 0u; groupNdx < DE_LENGTH_OF_ARRAY(locationsGroups); ++groupNdx)
1935 {
1936 // Single subpass cases
1937 for (deUint32 caseNdx = 0u; caseNdx < DE_LENGTH_OF_ARRAY(singlePassCases); ++caseNdx)
1938 {
1939 VerifySamples::TestParams::SampleCount samples;
1940 samples.numColorSamples = singlePassCases[caseNdx].colorSamples;
1941 samples.numDepthStencilSamples = singlePassCases[caseNdx].depthStencilSamples;
1942 samples.numCoverageSamples = de::max(samples.numColorSamples, samples.numDepthStencilSamples);
1943
1944 VerifySamples::TestParams params;
1945 params.perSubpassSamples.push_back(samples);
1946 params.useProgrammableSampleLocations = (locationsGroups[groupNdx] == programmableLocationsGroup.get());
1947
1948 MovePtr<tcu::TestCaseGroup> sampleCaseGroup(new tcu::TestCaseGroup(
1949 rootGroup->getTestContext(), getSampleCountGroupName(samples.numCoverageSamples, samples.numColorSamples, samples.numDepthStencilSamples).c_str(), ""));
1950
1951 for (const VkFormat *pDepthStencilFormat = depthStencilFormatRange; pDepthStencilFormat != DE_ARRAY_END(depthStencilFormatRange); ++pDepthStencilFormat)
1952 for (const VkFormat *pColorFormat = colorFormatRange; pColorFormat != DE_ARRAY_END(colorFormatRange); ++pColorFormat)
1953 {
1954 params.colorFormat = *pColorFormat;
1955 params.depthStencilFormat = *pDepthStencilFormat;
1956
1957 addFunctionCaseWithPrograms(
1958 sampleCaseGroup.get(),
1959 getFormatCaseName(params.colorFormat, params.depthStencilFormat).c_str(),
1960 "",
1961 VerifySamples::checkRequirements,
1962 VerifySamples::initPrograms,
1963 VerifySamples::test, params);
1964 }
1965
1966 locationsGroups[groupNdx]->addChild(sampleCaseGroup.release());
1967 }
1968
1969 // Multi subpass cases
1970 for (deUint32 caseNdx = 0u; caseNdx < DE_LENGTH_OF_ARRAY(subpassCases); ++caseNdx)
1971 {
1972 VerifySamples::TestParams params;
1973 params.useProgrammableSampleLocations = (locationsGroups[groupNdx] == programmableLocationsGroup.get());
1974
1975 for (deUint32 subpassNdx = 0; subpassNdx < subpassCases[caseNdx].numSampleCases; ++subpassNdx)
1976 {
1977 VerifySamples::TestParams::SampleCount samples;
1978 samples.numColorSamples = subpassCases[caseNdx].pSampleCase[subpassNdx].colorSamples;
1979 samples.numDepthStencilSamples = subpassCases[caseNdx].pSampleCase[subpassNdx].depthStencilSamples;
1980 samples.numCoverageSamples = de::max(samples.numColorSamples, samples.numDepthStencilSamples);
1981 params.perSubpassSamples.push_back(samples);
1982 }
1983
1984 MovePtr<tcu::TestCaseGroup> sampleCaseGroup(new tcu::TestCaseGroup(rootGroup->getTestContext(), subpassCases[caseNdx].caseName, ""));
1985
1986 for (const VkFormat *pDepthStencilFormat = depthStencilReducedFormatRange; pDepthStencilFormat != DE_ARRAY_END(depthStencilReducedFormatRange); ++pDepthStencilFormat)
1987 for (const VkFormat *pColorFormat = colorFormatRange; pColorFormat != DE_ARRAY_END(colorFormatRange); ++pColorFormat)
1988 {
1989 params.colorFormat = *pColorFormat;
1990 params.depthStencilFormat = *pDepthStencilFormat;
1991
1992 addFunctionCaseWithPrograms(
1993 sampleCaseGroup.get(),
1994 getFormatCaseName(params.colorFormat, params.depthStencilFormat).c_str(),
1995 "",
1996 VerifySamples::checkRequirements,
1997 VerifySamples::initPrograms,
1998 VerifySamples::test, params);
1999 }
2000
2001 locationsGroups[groupNdx]->addChild(sampleCaseGroup.release());
2002 }
2003 }
2004
2005 rootGroup->addChild(standardLocationsGroup.release());
2006 rootGroup->addChild(programmableLocationsGroup.release());
2007 }
2008
2009 // Test 2: Shader built-ins check
2010 {
2011 MovePtr<tcu::TestCaseGroup> builtinsGroup (new tcu::TestCaseGroup(rootGroup->getTestContext(), "shader_builtins", ""));
2012
2013 for (deUint32 caseNdx = 0u; caseNdx < DE_LENGTH_OF_ARRAY(singlePassCases); ++caseNdx)
2014 {
2015 ShaderBuiltins::TestParams params;
2016 params.numColorSamples = singlePassCases[caseNdx].colorSamples;
2017 params.numDepthStencilSamples = singlePassCases[caseNdx].depthStencilSamples;
2018 params.numCoverageSamples = de::max(params.numColorSamples, params.numDepthStencilSamples);
2019
2020 MovePtr<tcu::TestCaseGroup> sampleCaseGroup(new tcu::TestCaseGroup(
2021 rootGroup->getTestContext(), getSampleCountGroupName(params.numCoverageSamples, params.numColorSamples, params.numDepthStencilSamples).c_str(), ""));
2022
2023 for (const VkFormat *pDepthStencilFormat = depthStencilReducedFormatRange; pDepthStencilFormat != DE_ARRAY_END(depthStencilReducedFormatRange); ++pDepthStencilFormat)
2024 for (const VkFormat *pColorFormat = colorFormatRange; pColorFormat != DE_ARRAY_END(colorFormatRange); ++pColorFormat)
2025 {
2026 params.colorFormat = *pColorFormat;
2027 params.depthStencilFormat = *pDepthStencilFormat;
2028
2029 addFunctionCaseWithPrograms(
2030 sampleCaseGroup.get(),
2031 getFormatCaseName(params.colorFormat, params.depthStencilFormat).c_str(),
2032 "",
2033 ShaderBuiltins::checkRequirements,
2034 ShaderBuiltins::initPrograms,
2035 ShaderBuiltins::test,
2036 params);
2037 }
2038
2039 builtinsGroup->addChild(sampleCaseGroup.release());
2040 }
2041
2042 rootGroup->addChild(builtinsGroup.release());
2043 }
2044 }
2045
2046 } // anonymous ns
2047
createMultisampleMixedAttachmentSamplesTests(tcu::TestContext & testCtx)2048 tcu::TestCaseGroup* createMultisampleMixedAttachmentSamplesTests (tcu::TestContext& testCtx)
2049 {
2050 return createTestGroup(testCtx, "mixed_attachment_samples", "Test a graphics pipeline with varying sample count per color and depth/stencil attachments", createMixedAttachmentSamplesTestsInGroup);
2051 }
2052
2053 } // pipeline
2054 } // vkt
2055