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