1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2022 The Khronos Group Inc.
6 * Copyright (c) 2022 Google Inc.
7 * Copyright (c) 2023 LunarG, Inc.
8 * Copyright (c) 2023 Nintendo
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 *
22 *//*!
23 * \file vktPipelineMultisampleResolveRenderAreaTests.hpp
24 * \brief Multisample resolve tests where a render area is less than an
25 * attachment size.
26 *//*--------------------------------------------------------------------*/
27
28 #include "vktPipelineMultisampleResolveRenderAreaTests.hpp"
29 #include "vktTestCaseUtil.hpp"
30 #include "vktTestGroupUtil.hpp"
31
32 #include "vkCmdUtil.hpp"
33 #include "vkImageUtil.hpp"
34 #include "vkMemUtil.hpp"
35 #include "vkObjUtil.hpp"
36 #include "vkRefUtil.hpp"
37 #include "vkTypeUtil.hpp"
38
39 #include "tcuImageCompare.hpp"
40 #include "tcuTestLog.hpp"
41
42 namespace vkt
43 {
44 namespace pipeline
45 {
46 using namespace vk;
47 using de::UniquePtr;
48
49 namespace
50 {
51
52 enum class TestShape
53 {
54 SHAPE_RECTANGLE,
55 SHAPE_DIAMOND,
56 SHAPE_PARALLELOGRAM
57 };
58
59 class MultisampleRenderAreaTestInstance : public TestInstance
60 {
61 public:
MultisampleRenderAreaTestInstance(Context & context,const PipelineConstructionType pipelineConstructionType,const uint32_t sampleCount,const tcu::IVec2 framebufferSize,const TestShape testShape,const VkFormat colorFormat)62 MultisampleRenderAreaTestInstance(Context &context, const PipelineConstructionType pipelineConstructionType,
63 const uint32_t sampleCount, const tcu::IVec2 framebufferSize,
64 const TestShape testShape, const VkFormat colorFormat)
65 : TestInstance(context)
66 , m_pipelineConstructionType(pipelineConstructionType)
67 , m_sampleCount(sampleCount)
68 , m_framebufferSize(framebufferSize)
69 , m_testShape(testShape)
70 , m_colorFormat(colorFormat)
71 {
72 }
73
74 tcu::TestStatus iterate(void);
75
76 private:
77 VkImageCreateInfo makeImageCreateInfo(const tcu::IVec2 &imageSize, const uint32_t sampleCount);
78
79 RenderPassWrapper makeRenderPass(const DeviceInterface &vk, const VkDevice device, const VkFormat colorFormat,
80 const VkImageLayout initialLayout);
81
82 void preparePipelineWrapper(GraphicsPipelineWrapper &gpw, const PipelineLayoutWrapper &pipelineLayout,
83 const VkRenderPass renderPass, const ShaderWrapper vertexModule,
84 const ShaderWrapper fragmentModule, const tcu::IVec2 &framebufferSize);
85
86 const PipelineConstructionType m_pipelineConstructionType;
87 const uint32_t m_sampleCount;
88 const tcu::IVec2 m_framebufferSize;
89 const TestShape m_testShape;
90 const VkFormat m_colorFormat;
91 };
92
makeImageCreateInfo(const tcu::IVec2 & imageSize,const uint32_t sampleCount)93 VkImageCreateInfo MultisampleRenderAreaTestInstance::makeImageCreateInfo(const tcu::IVec2 &imageSize,
94 const uint32_t sampleCount)
95 {
96 const VkImageCreateInfo imageParams = {
97 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
98 DE_NULL, // const void* pNext;
99 (VkImageCreateFlags)0, // VkImageCreateFlags flags;
100 VK_IMAGE_TYPE_2D, // VkImageType imageType;
101 m_colorFormat, // VkFormat format;
102 makeExtent3D(imageSize.x(), imageSize.y(), 1), // VkExtent3D extent;
103 1u, // uint32_t mipLevels;
104 1u, // uint32_t arrayLayers;
105 sampleCount < 2u ? VK_SAMPLE_COUNT_1_BIT :
106 (VkSampleCountFlagBits)m_sampleCount, // VkSampleCountFlagBits samples;
107 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
108 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, // VkImageUsageFlags usage;
109 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
110 0u, // uint32_t queueFamilyIndexCount;
111 DE_NULL, // const uint32_t* pQueueFamilyIndices;
112 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
113 };
114
115 return imageParams;
116 }
117
makeRenderPass(const DeviceInterface & vk,const VkDevice device,const VkFormat colorFormat,const VkImageLayout initialLayout)118 RenderPassWrapper MultisampleRenderAreaTestInstance::makeRenderPass(const DeviceInterface &vk, const VkDevice device,
119 const VkFormat colorFormat,
120 const VkImageLayout initialLayout)
121 {
122 const VkAttachmentDescription colorAttachmentDescription = {
123 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags;
124 colorFormat, // VkFormat format;
125 (VkSampleCountFlagBits)m_sampleCount, // VkSampleCountFlagBits samples;
126 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
127 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
128 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
129 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
130 initialLayout, // VkImageLayout initialLayout;
131 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout;
132 };
133
134 const VkAttachmentDescription resolveAttachmentDescription = {
135 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags;
136 colorFormat, // VkFormat format;
137 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
138 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
139 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
140 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
141 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
142 initialLayout, // VkImageLayout initialLayout;
143 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout;
144 };
145
146 std::vector<VkAttachmentDescription> attachmentDescriptions;
147
148 attachmentDescriptions.push_back(colorAttachmentDescription);
149 attachmentDescriptions.push_back(resolveAttachmentDescription);
150
151 const VkAttachmentReference colorAttachmentRef = {
152 0u, // uint32_t attachment;
153 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
154 };
155
156 const VkAttachmentReference resolveAttachmentRef = {
157 1u, // uint32_t attachment;
158 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
159 };
160
161 const VkSubpassDescription subpassDescription = {
162 (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags;
163 VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
164 0u, // uint32_t inputAttachmentCount;
165 DE_NULL, // const VkAttachmentReference* pInputAttachments;
166 1u, // uint32_t colorAttachmentCount;
167 &colorAttachmentRef, // const VkAttachmentReference* pColorAttachments;
168 &resolveAttachmentRef, // const VkAttachmentReference* pResolveAttachments;
169 DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment;
170 0u, // uint32_t preserveAttachmentCount;
171 DE_NULL // const uint32_t* pPreserveAttachments;
172 };
173
174 const VkRenderPassCreateInfo renderPassInfo = {
175 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
176 DE_NULL, // const void* pNext;
177 (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags;
178 (uint32_t)attachmentDescriptions.size(), // uint32_t attachmentCount;
179 attachmentDescriptions.data(), // const VkAttachmentDescription* pAttachments;
180 1u, // uint32_t subpassCount;
181 &subpassDescription, // const VkSubpassDescription* pSubpasses;
182 0u, // uint32_t dependencyCount;
183 DE_NULL, // const VkSubpassDependency* pDependencies;
184 };
185
186 return RenderPassWrapper(m_pipelineConstructionType, vk, device, &renderPassInfo);
187 }
188
preparePipelineWrapper(GraphicsPipelineWrapper & gpw,const PipelineLayoutWrapper & pipelineLayout,const VkRenderPass renderPass,const ShaderWrapper vertexModule,const ShaderWrapper fragmentModule,const tcu::IVec2 & framebufferSize)189 void MultisampleRenderAreaTestInstance::preparePipelineWrapper(
190 GraphicsPipelineWrapper &gpw, const PipelineLayoutWrapper &pipelineLayout, const VkRenderPass renderPass,
191 const ShaderWrapper vertexModule, const ShaderWrapper fragmentModule, const tcu::IVec2 &framebufferSize)
192 {
193 const std::vector<VkViewport> viewports{makeViewport(framebufferSize)};
194 const std::vector<VkRect2D> scissors{makeRect2D(framebufferSize)};
195 VkSampleMask sampleMask = 0xffff;
196
197 const VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo{
198 VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType
199 DE_NULL, // const void* pNext
200 0u, // VkPipelineMultisampleStateCreateFlags flags
201 (VkSampleCountFlagBits)m_sampleCount, // VkSampleCountFlagBits rasterizationSamples
202 false, // VkBool32 sampleShadingEnable
203 0.0f, // float minSampleShading
204 &sampleMask, // const VkSampleMask* pSampleMask
205 false, // VkBool32 alphaToCoverageEnable
206 false, // VkBool32 alphaToOneEnable
207 };
208
209 gpw.setDefaultDepthStencilState()
210 .setDefaultColorBlendState()
211 .setDefaultRasterizationState()
212 .setupVertexInputState()
213 .setupPreRasterizationShaderState(viewports, scissors, pipelineLayout, renderPass, 0u, vertexModule)
214 .setupFragmentShaderState(pipelineLayout, renderPass, 0u, fragmentModule, DE_NULL, &multisampleStateCreateInfo)
215 .setupFragmentOutputState(renderPass, 0u, DE_NULL, &multisampleStateCreateInfo)
216 .setMonolithicPipelineLayout(pipelineLayout)
217 .buildPipeline();
218 }
219
iterate(void)220 tcu::TestStatus MultisampleRenderAreaTestInstance::iterate(void)
221 {
222 const InstanceInterface &vki = m_context.getInstanceInterface();
223 const DeviceInterface &vk = m_context.getDeviceInterface();
224 const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
225 const VkDevice device = m_context.getDevice();
226 Allocator &allocator = m_context.getDefaultAllocator();
227 const VkQueue queue = m_context.getUniversalQueue();
228 const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
229 const VkImageSubresourceRange colorSubresourceRange =
230 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
231
232 const ShaderWrapper vertexModule(ShaderWrapper(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
233 const ShaderWrapper fragmentModule(ShaderWrapper(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
234
235 const Unique<VkImage> colorImage(makeImage(vk, device, makeImageCreateInfo(m_framebufferSize, m_sampleCount)));
236 const UniquePtr<Allocation> colorImageAlloc(bindImage(vk, device, allocator, *colorImage, MemoryRequirement::Any));
237 const Unique<VkImageView> colorImageView(
238 makeImageView(vk, device, *colorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, colorSubresourceRange));
239
240 const Unique<VkImage> resolveColorImage(makeImage(vk, device, makeImageCreateInfo(m_framebufferSize, 1u)));
241 const UniquePtr<Allocation> resolveColorImageAlloc(
242 bindImage(vk, device, allocator, *resolveColorImage, MemoryRequirement::Any));
243 const Unique<VkImageView> resolveColorImageView(
244 makeImageView(vk, device, *resolveColorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, colorSubresourceRange));
245
246 const VkImage images[] = {*colorImage, *resolveColorImage};
247 const VkImageView attachmentImages[] = {*colorImageView, *resolveColorImageView};
248 const uint32_t numUsedAttachmentImages = DE_LENGTH_OF_ARRAY(attachmentImages);
249
250 const VkDeviceSize colorBufferSizeBytes =
251 tcu::getPixelSize(mapVkFormat(m_colorFormat)) * m_framebufferSize.x() * m_framebufferSize.y();
252 const Unique<VkBuffer> colorBufferResults(
253 makeBuffer(vk, device, colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
254 const UniquePtr<Allocation> colorBufferAlloc(
255 bindBuffer(vk, device, allocator, *colorBufferResults, MemoryRequirement::HostVisible));
256
257 RenderPassWrapper renderPassOne(makeRenderPass(vk, device, m_colorFormat, VK_IMAGE_LAYOUT_UNDEFINED));
258 RenderPassWrapper renderPassTwo(
259 makeRenderPass(vk, device, m_colorFormat, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
260 renderPassOne.createFramebuffer(vk, device, numUsedAttachmentImages, images, attachmentImages,
261 m_framebufferSize.x(), m_framebufferSize.y());
262 renderPassTwo.createFramebuffer(vk, device, numUsedAttachmentImages, images, attachmentImages,
263 m_framebufferSize.x(), m_framebufferSize.y());
264
265 const PipelineLayoutWrapper pipelineLayout(m_pipelineConstructionType, vk, device);
266 GraphicsPipelineWrapper graphicsPipeline{
267 vki, vk, physicalDevice, device, m_context.getDeviceExtensions(), m_pipelineConstructionType};
268
269 const Unique<VkCommandPool> cmdPool(
270 createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
271 const Unique<VkCommandBuffer> commandBuffer(
272 allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
273
274 // Main vertex buffer
275 const uint32_t numVertices = 6;
276 const VkDeviceSize vertexBufferSizeBytes = 256;
277 const Unique<VkBuffer> vertexBuffer(
278 makeBuffer(vk, device, vertexBufferSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
279 const UniquePtr<Allocation> vertexBufferAlloc(
280 bindBuffer(vk, device, allocator, *vertexBuffer, MemoryRequirement::HostVisible));
281
282 preparePipelineWrapper(graphicsPipeline, pipelineLayout, *renderPassOne, vertexModule, fragmentModule,
283 m_framebufferSize);
284
285 {
286 tcu::Vec4 *const pVertices = reinterpret_cast<tcu::Vec4 *>(vertexBufferAlloc->getHostPtr());
287
288 // The shapes should fit just and just inside the renderArea.
289 if (m_testShape == TestShape::SHAPE_RECTANGLE)
290 {
291 float size = 0.5f;
292
293 pVertices[0] = tcu::Vec4(size, -size, 0.0f, 1.0f);
294 pVertices[1] = tcu::Vec4(-size, -size, 0.0f, 1.0f);
295 pVertices[2] = tcu::Vec4(-size, size, 0.0f, 1.0f);
296
297 pVertices[3] = tcu::Vec4(-size, size, 0.0f, 1.0f);
298 pVertices[4] = tcu::Vec4(size, size, 0.0f, 1.0f);
299 pVertices[5] = tcu::Vec4(size, -size, 0.0f, 1.0f);
300 }
301
302 if (m_testShape == TestShape::SHAPE_DIAMOND)
303 {
304 float size = 0.5f;
305
306 pVertices[0] = tcu::Vec4(size, 0.0f, 0.0f, 1.0f);
307 pVertices[1] = tcu::Vec4(-0.0f, -size, 0.0f, 1.0f);
308 pVertices[2] = tcu::Vec4(-size, 0.0f, 0.0f, 1.0f);
309
310 pVertices[3] = tcu::Vec4(size, 0.0f, 0.0f, 1.0f);
311 pVertices[4] = tcu::Vec4(-size, 0.0f, 0.0f, 1.0f);
312 pVertices[5] = tcu::Vec4(-0.0f, size, 0.0f, 1.0f);
313 }
314
315 if (m_testShape == TestShape::SHAPE_PARALLELOGRAM)
316 {
317 float size = 0.3125f;
318
319 pVertices[0] = tcu::Vec4(size, -size, 0.0f, 1.0f);
320 pVertices[1] = tcu::Vec4(-0.5f, -size, 0.0f, 1.0f);
321 pVertices[2] = tcu::Vec4(-size, size, 0.0f, 1.0f);
322
323 pVertices[3] = tcu::Vec4(-size, size, 0.0f, 1.0f);
324 pVertices[4] = tcu::Vec4(0.5f, size, 0.0f, 1.0f);
325 pVertices[5] = tcu::Vec4(size, -size, 0.0f, 1.0f);
326 }
327
328 flushAlloc(vk, device, *vertexBufferAlloc);
329 }
330
331 const VkDeviceSize vertexBufferOffset = 0ull;
332
333 const VkRect2D testRenderArea = {
334 makeOffset2D(m_framebufferSize.x() / 4u, m_framebufferSize.x() / 4u),
335 makeExtent2D(m_framebufferSize.x() / 2u, m_framebufferSize.y() / 2u),
336 };
337
338 const std::vector<VkClearValue> clearValuesFullArea = {makeClearValueColor(tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)),
339 makeClearValueColor(tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f))};
340 const std::vector<VkClearValue> clearValuesTestArea = {makeClearValueColor(tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f)),
341 makeClearValueColor(tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f))};
342
343 beginCommandBuffer(vk, *commandBuffer);
344
345 const VkRect2D fullRenderArea = {
346 makeOffset2D(0u, 0u),
347 makeExtent2D(m_framebufferSize.x(), m_framebufferSize.y()),
348 };
349
350 // Clear whole render area with red color.
351 renderPassOne.begin(vk, *commandBuffer, fullRenderArea, static_cast<uint32_t>(clearValuesFullArea.size()),
352 clearValuesFullArea.data());
353 renderPassTwo.end(vk, *commandBuffer);
354
355 // Draw shape when render area size is halved.
356 renderPassTwo.begin(vk, *commandBuffer, testRenderArea, static_cast<uint32_t>(clearValuesTestArea.size()),
357 clearValuesTestArea.data());
358 vk.cmdBindVertexBuffers(*commandBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
359 graphicsPipeline.bind(*commandBuffer);
360 vk.cmdDraw(*commandBuffer, numVertices, 1u, 0u, 0u);
361 renderPassTwo.end(vk, *commandBuffer);
362
363 copyImageToBuffer(vk, *commandBuffer, *resolveColorImage, *colorBufferResults, m_framebufferSize,
364 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
365
366 endCommandBuffer(vk, *commandBuffer);
367 submitCommandsAndWait(vk, device, queue, *commandBuffer);
368
369 // Verify color output
370 {
371 invalidateAlloc(vk, device, *colorBufferAlloc);
372
373 tcu::TestLog &log = m_context.getTestContext().getLog();
374 const Unique<VkBuffer> testBufferResults(
375 makeBuffer(vk, device, colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
376 tcu::ConstPixelBufferAccess imageAccess(mapVkFormat(m_colorFormat), m_framebufferSize.x(),
377 m_framebufferSize.y(), 1, colorBufferAlloc->getHostPtr());
378
379 // Color check for rendered shape. Shape color is yellow.
380 if (imageAccess.getPixel(m_framebufferSize.x() / 2, m_framebufferSize.y() / 2) !=
381 tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f))
382 {
383 log << tcu::TestLog::Image("color0", "Rendered image", imageAccess);
384 return tcu::TestStatus::fail("Pixel check failed: shape color");
385 }
386
387 // Color check for the second render area. Clear color should be green.
388 if (m_testShape != TestShape::SHAPE_RECTANGLE) // In this case the shape has covered the whole render area.
389 {
390 if (imageAccess.getPixel(m_framebufferSize.x() / 4 + 1, m_framebufferSize.y() / 4 + 1) !=
391 tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f))
392 {
393 log << tcu::TestLog::Image("color0", "Rendered image", imageAccess);
394 return tcu::TestStatus::fail("Pixel check failed inside the render area");
395 }
396 }
397
398 // Color check for possible overflowed multisample pixels outside of the second render area.
399 // Clear color after the first beginRenderPass should be red.
400 const int minValue = m_framebufferSize.y() / 4 - 1;
401 const int maxValue = m_framebufferSize.y() - m_framebufferSize.y() / 4;
402
403 for (int y = 0; y < m_framebufferSize.y(); y++)
404 {
405 for (int x = 0; x < m_framebufferSize.x(); x++)
406 {
407 if (!(x > minValue && y > minValue && x < maxValue && y < maxValue))
408 {
409 if (imageAccess.getPixel(x, y) != tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f))
410 {
411 log << tcu::TestLog::Message << "Incorrect color value " << imageAccess.getPixel(x, y)
412 << " at location (" << x << ", " << y << ")" << tcu::TestLog::EndMessage;
413 log << tcu::TestLog::Image("color0", "Rendered image", imageAccess);
414 return tcu::TestStatus::fail("Pixel check failed outside the render area");
415 }
416 }
417 }
418 }
419 }
420
421 return tcu::TestStatus::pass("Success");
422 }
423
424 class MultisampleRenderAreaTest : public TestCase
425 {
426 public:
MultisampleRenderAreaTest(tcu::TestContext & testCtx,const std::string name,const PipelineConstructionType pipelineConstructionType,const uint32_t sampleCount,const tcu::IVec2 framebufferSize,const TestShape testShape,const VkFormat colorFormat=VK_FORMAT_R8G8B8A8_UNORM)427 MultisampleRenderAreaTest(tcu::TestContext &testCtx, const std::string name,
428 const PipelineConstructionType pipelineConstructionType, const uint32_t sampleCount,
429 const tcu::IVec2 framebufferSize, const TestShape testShape,
430 const VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM)
431 : TestCase(testCtx, name)
432 , m_pipelineConstructionType(pipelineConstructionType)
433 , m_sampleCount(sampleCount)
434 , m_framebufferSize(framebufferSize)
435 , m_testShape(testShape)
436 , m_colorFormat(colorFormat)
437 {
438 }
439
440 void initPrograms(SourceCollections &programCollection) const;
441 TestInstance *createInstance(Context &context) const;
442 virtual void checkSupport(Context &context) const;
443
444 private:
445 const PipelineConstructionType m_pipelineConstructionType;
446 const uint32_t m_sampleCount;
447 const tcu::IVec2 m_framebufferSize;
448 const TestShape m_testShape;
449 const VkFormat m_colorFormat;
450 };
451
initPrograms(SourceCollections & programCollection) const452 void MultisampleRenderAreaTest::initPrograms(SourceCollections &programCollection) const
453 {
454 // Vertex shader
455 {
456 std::ostringstream src;
457 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
458 << "\n"
459 << "layout(location = 0) in vec4 position;\n"
460 << "\n"
461 << "void main (void)\n"
462 << "{\n"
463 << " gl_Position = position;\n"
464 << "}\n";
465
466 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
467 }
468
469 // Fragment shader
470 {
471 std::ostringstream frg;
472 frg << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
473 << "\n"
474 << "layout(location = 0) out vec4 fragColor;\n"
475 << "\n"
476 << "void main (void)\n"
477 << "{\n"
478 << " fragColor = vec4(1.0, 1.0, 0.0, 1.0);\n"
479 << "}\n";
480
481 programCollection.glslSources.add("frag") << glu::FragmentSource(frg.str());
482 }
483 }
484
createInstance(Context & context) const485 TestInstance *MultisampleRenderAreaTest::createInstance(Context &context) const
486 {
487 return new MultisampleRenderAreaTestInstance(context, m_pipelineConstructionType, m_sampleCount, m_framebufferSize,
488 m_testShape, m_colorFormat);
489 }
490
checkSupport(Context & context) const491 void MultisampleRenderAreaTest::checkSupport(Context &context) const
492 {
493 // Check support for MSAA image format used in the test.
494 const InstanceInterface &vki = context.getInstanceInterface();
495 const VkPhysicalDevice physDevice = context.getPhysicalDevice();
496
497 VkImageFormatProperties formatProperties;
498
499 vki.getPhysicalDeviceImageFormatProperties(physDevice, m_colorFormat, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL,
500 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
501 0u, &formatProperties);
502
503 if ((formatProperties.sampleCounts & m_sampleCount) == 0)
504 TCU_THROW(NotSupportedError, "Format does not support this number of samples");
505
506 checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
507 m_pipelineConstructionType);
508 }
509
510 } // namespace
511
createMultisampleResolveRenderpassRenderAreaTests(tcu::TestContext & testCtx,PipelineConstructionType pipelineConstructionType)512 tcu::TestCaseGroup *createMultisampleResolveRenderpassRenderAreaTests(tcu::TestContext &testCtx,
513 PipelineConstructionType pipelineConstructionType)
514 {
515 // resolving multisample image tests
516 de::MovePtr<tcu::TestCaseGroup> testGroupResolve(new tcu::TestCaseGroup(testCtx, "resolve"));
517
518 // renderpass render area tests
519 de::MovePtr<tcu::TestCaseGroup> testGroupRenderArea(new tcu::TestCaseGroup(testCtx, "renderpass_renderarea"));
520
521 static const struct
522 {
523 std::string shapeName;
524 TestShape testShape;
525 } shapes[] = {{"rectangle", TestShape::SHAPE_RECTANGLE},
526 {"diamond", TestShape::SHAPE_DIAMOND},
527 {"parallelogram", TestShape::SHAPE_PARALLELOGRAM}};
528
529 static const struct
530 {
531 std::string caseName;
532 const uint32_t sampleCount;
533 } cases[] = {
534 {
535 "samples_2",
536 2u,
537 },
538 {
539 "samples_4",
540 4u,
541 },
542 {
543 "samples_8",
544 8u,
545 },
546 {"samples_16", 16u},
547 };
548
549 for (const auto &testShape : shapes)
550 {
551 for (const auto &testCase : cases)
552 {
553 testGroupRenderArea->addChild(new MultisampleRenderAreaTest(
554 testCtx, testShape.shapeName + "_" + testCase.caseName, pipelineConstructionType, testCase.sampleCount,
555 tcu::IVec2(32, 32), testShape.testShape));
556 }
557 }
558
559 testGroupResolve->addChild(testGroupRenderArea.release());
560
561 return testGroupResolve.release();
562 }
563
564 } // namespace pipeline
565 } // namespace vkt
566