xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/draw/vktDrawDiscardRectanglesTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2019 Valve Corporation.
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 EXT_discard_rectangles tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktDrawDiscardRectanglesTests.hpp"
26 
27 #include "vkDefs.hpp"
28 #include "vkRef.hpp"
29 #include "vkRefUtil.hpp"
30 #include "vkTypeUtil.hpp"
31 #include "vkImageUtil.hpp"
32 #include "vkMemUtil.hpp"
33 #include "vkObjUtil.hpp"
34 #include "vkCmdUtil.hpp"
35 #include "vkQueryUtil.hpp"
36 #include "vktTestGroupUtil.hpp"
37 #include "vktTestCase.hpp"
38 #include "vktDrawBufferObjectUtil.hpp"
39 #include "vktDrawImageObjectUtil.hpp"
40 
41 #include "tcuTestCase.hpp"
42 #include "tcuVector.hpp"
43 #include "tcuTextureUtil.hpp"
44 #include "tcuTextureUtil.hpp"
45 #include "tcuImageCompare.hpp"
46 
47 #include "deUniquePtr.hpp"
48 #include "deSharedPtr.hpp"
49 
50 namespace vkt
51 {
52 namespace Draw
53 {
54 
55 namespace
56 {
57 using namespace vk;
58 using de::MovePtr;
59 using de::SharedPtr;
60 using de::UniquePtr;
61 using tcu::UVec2;
62 using tcu::UVec4;
63 using tcu::Vec2;
64 using tcu::Vec4;
65 
66 enum TestMode
67 {
68     TEST_MODE_INCLUSIVE = 0,
69     TEST_MODE_EXCLUSIVE,
70     TEST_MODE_COUNT
71 };
72 
73 enum TestScissorMode
74 {
75     TEST_SCISSOR_MODE_NONE = 0,
76     TEST_SCISSOR_MODE_STATIC,
77     TEST_SCISSOR_MODE_DYNAMIC,
78     TEST_SCISSOR_MODE_COUNT
79 };
80 
81 #define NUM_RECT_TESTS 6
82 #define NUM_DYNAMIC_DISCARD_TYPE_TESTS 2
83 
84 struct TestParams
85 {
86     TestMode testMode;
87     uint32_t numRectangles;
88     bool dynamicDiscardRectangles;
89     TestScissorMode scissorMode;
90     const SharedGroupParams groupParams;
91 };
92 
93 template <typename T>
sizeInBytes(const std::vector<T> & vec)94 inline VkDeviceSize sizeInBytes(const std::vector<T> &vec)
95 {
96     return vec.size() * sizeof(vec[0]);
97 }
98 
makeImageCreateInfo(const VkFormat format,const UVec2 & size,VkImageUsageFlags usage)99 VkImageCreateInfo makeImageCreateInfo(const VkFormat format, const UVec2 &size, VkImageUsageFlags usage)
100 {
101     const VkImageCreateInfo imageParams = {
102         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
103         DE_NULL,                             // const void* pNext;
104         (VkImageCreateFlags)0,               // VkImageCreateFlags flags;
105         VK_IMAGE_TYPE_2D,                    // VkImageType imageType;
106         format,                              // VkFormat format;
107         makeExtent3D(size.x(), size.y(), 1), // VkExtent3D extent;
108         1u,                                  // uint32_t mipLevels;
109         1u,                                  // uint32_t arrayLayers;
110         VK_SAMPLE_COUNT_1_BIT,               // VkSampleCountFlagBits samples;
111         VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling tiling;
112         usage,                               // VkImageUsageFlags usage;
113         VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
114         0u,                                  // uint32_t queueFamilyIndexCount;
115         DE_NULL,                             // const uint32_t* pQueueFamilyIndices;
116         VK_IMAGE_LAYOUT_UNDEFINED,           // VkImageLayout initialLayout;
117     };
118     return imageParams;
119 }
120 
makeDiscardRectangleStateCreateInfo(const bool dynamicDiscardRectangle,const VkDiscardRectangleModeEXT discardRectangleMode,const uint32_t discardRectangleCount,const VkRect2D * pDiscardRectangles)121 VkPipelineDiscardRectangleStateCreateInfoEXT makeDiscardRectangleStateCreateInfo(
122     const bool dynamicDiscardRectangle, const VkDiscardRectangleModeEXT discardRectangleMode,
123     const uint32_t discardRectangleCount, const VkRect2D *pDiscardRectangles)
124 {
125     const VkPipelineDiscardRectangleStateCreateInfoEXT discardRectanglesCreateInfo = {
126         VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT, // VkStructureType sType;
127         DE_NULL,                                                            // const void* pNext;
128         0u,                                                    // VkPipelineDiscardRectangleStateCreateFlagsEXT flags;
129         discardRectangleMode,                                  // VkDiscardRectangleModeEXT discardRectangleMode;
130         discardRectangleCount,                                 // uint32_t discardRectangleCount;
131         dynamicDiscardRectangle ? DE_NULL : pDiscardRectangles // const VkRect2D* pDiscardRectangles;
132     };
133     return discardRectanglesCreateInfo;
134 }
135 
makeGraphicsPipeline(const DeviceInterface & vk,const VkDevice device,const VkPipelineLayout pipelineLayout,const VkRenderPass renderPass,const VkShaderModule vertexModule,const VkShaderModule fragmentModule,const UVec2 renderSize,const bool dynamicDiscardRectangle,const VkDiscardRectangleModeEXT discardRectangleMode,const uint32_t discardRectangleCount,const VkRect2D * pDiscardRectangles,const TestScissorMode scissorMode,const VkRect2D rectScissor)136 Move<VkPipeline> makeGraphicsPipeline(const DeviceInterface &vk, const VkDevice device,
137                                       const VkPipelineLayout pipelineLayout, const VkRenderPass renderPass,
138                                       const VkShaderModule vertexModule, const VkShaderModule fragmentModule,
139                                       const UVec2 renderSize, const bool dynamicDiscardRectangle,
140                                       const VkDiscardRectangleModeEXT discardRectangleMode,
141                                       const uint32_t discardRectangleCount, const VkRect2D *pDiscardRectangles,
142                                       const TestScissorMode scissorMode, const VkRect2D rectScissor)
143 {
144     const VkVertexInputBindingDescription vertexInputBindingDescription = {
145         0u,                          // uint32_t binding;
146         sizeof(Vec4),                // uint32_t stride;
147         VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate;
148     };
149 
150     const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] = {
151         {
152             0u,                            // uint32_t location;
153             0u,                            // uint32_t binding;
154             VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
155             0u,                            // uint32_t offset;
156         },
157     };
158 
159     const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo = {
160         VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
161         DE_NULL,                                                   // const void* pNext;
162         (VkPipelineVertexInputStateCreateFlags)0,                  // VkPipelineVertexInputStateCreateFlags flags;
163         1u,                                                        // uint32_t vertexBindingDescriptionCount;
164         &vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
165         DE_LENGTH_OF_ARRAY(vertexInputAttributeDescriptions), // uint32_t vertexAttributeDescriptionCount;
166         vertexInputAttributeDescriptions, // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
167     };
168 
169     const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo = {
170         VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
171         DE_NULL,                                                     // const void* pNext;
172         (VkPipelineInputAssemblyStateCreateFlags)0,                  // VkPipelineInputAssemblyStateCreateFlags flags;
173         VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,                        // VkPrimitiveTopology topology;
174         VK_FALSE,                                                    // VkBool32 primitiveRestartEnable;
175     };
176 
177     VkViewport viewport =
178         makeViewport(0.0f, 0.0f, static_cast<float>(renderSize.x()), static_cast<float>(renderSize.y()), 0.0f, 1.0f);
179     const VkRect2D rectScissorRenderSize = {{0, 0}, {renderSize.x(), renderSize.y()}};
180 
181     const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo = {
182         VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType;
183         DE_NULL,                                               // const void* pNext;
184         (VkPipelineViewportStateCreateFlags)0,                 // VkPipelineViewportStateCreateFlags flags;
185         1u,                                                    // uint32_t viewportCount;
186         &viewport,                                             // const VkViewport* pViewports;
187         1u,                                                    // uint32_t scissorCount;
188         scissorMode != TEST_SCISSOR_MODE_NONE ? &rectScissor : &rectScissorRenderSize, // const VkRect2D* pScissors;
189     };
190 
191     const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo = {
192         VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
193         DE_NULL,                                                    // const void* pNext;
194         (VkPipelineRasterizationStateCreateFlags)0,                 // VkPipelineRasterizationStateCreateFlags flags;
195         VK_FALSE,                                                   // VkBool32 depthClampEnable;
196         VK_FALSE,                                                   // VkBool32 rasterizerDiscardEnable;
197         VK_POLYGON_MODE_FILL,                                       // VkPolygonMode polygonMode;
198         VK_CULL_MODE_NONE,                                          // VkCullModeFlags cullMode;
199         VK_FRONT_FACE_COUNTER_CLOCKWISE,                            // VkFrontFace frontFace;
200         VK_FALSE,                                                   // VkBool32 depthBiasEnable;
201         0.0f,                                                       // float depthBiasConstantFactor;
202         0.0f,                                                       // float depthBiasClamp;
203         0.0f,                                                       // float depthBiasSlopeFactor;
204         1.0f,                                                       // float lineWidth;
205     };
206 
207     const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo = {
208         VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
209         DE_NULL,                                                  // const void* pNext;
210         (VkPipelineMultisampleStateCreateFlags)0,                 // VkPipelineMultisampleStateCreateFlags flags;
211         VK_SAMPLE_COUNT_1_BIT,                                    // VkSampleCountFlagBits rasterizationSamples;
212         VK_FALSE,                                                 // VkBool32 sampleShadingEnable;
213         0.0f,                                                     // float minSampleShading;
214         DE_NULL,                                                  // const VkSampleMask* pSampleMask;
215         VK_FALSE,                                                 // VkBool32 alphaToCoverageEnable;
216         VK_FALSE                                                  // VkBool32 alphaToOneEnable;
217     };
218 
219     const VkStencilOpState stencilOpState = makeStencilOpState(VK_STENCIL_OP_KEEP,   // stencil fail
220                                                                VK_STENCIL_OP_KEEP,   // depth & stencil pass
221                                                                VK_STENCIL_OP_KEEP,   // depth only fail
222                                                                VK_COMPARE_OP_ALWAYS, // compare op
223                                                                0u,                   // compare mask
224                                                                0u,                   // write mask
225                                                                0u);                  // reference
226 
227     VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo = {
228         VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
229         DE_NULL,                                                    // const void* pNext;
230         (VkPipelineDepthStencilStateCreateFlags)0,                  // VkPipelineDepthStencilStateCreateFlags flags;
231         VK_FALSE,                                                   // VkBool32 depthTestEnable;
232         VK_FALSE,                                                   // VkBool32 depthWriteEnable;
233         VK_COMPARE_OP_LESS,                                         // VkCompareOp depthCompareOp;
234         VK_FALSE,                                                   // VkBool32 depthBoundsTestEnable;
235         VK_FALSE,                                                   // VkBool32 stencilTestEnable;
236         stencilOpState,                                             // VkStencilOpState front;
237         stencilOpState,                                             // VkStencilOpState back;
238         0.0f,                                                       // float minDepthBounds;
239         1.0f,                                                       // float maxDepthBounds;
240     };
241 
242     const VkColorComponentFlags colorComponentsAll =
243         VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
244     const VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState = {
245         VK_FALSE,             // VkBool32 blendEnable;
246         VK_BLEND_FACTOR_ONE,  // VkBlendFactor srcColorBlendFactor;
247         VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor;
248         VK_BLEND_OP_ADD,      // VkBlendOp colorBlendOp;
249         VK_BLEND_FACTOR_ONE,  // VkBlendFactor srcAlphaBlendFactor;
250         VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor;
251         VK_BLEND_OP_ADD,      // VkBlendOp alphaBlendOp;
252         colorComponentsAll,   // VkColorComponentFlags colorWriteMask;
253     };
254 
255     const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo = {
256         VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
257         DE_NULL,                                                  // const void* pNext;
258         (VkPipelineColorBlendStateCreateFlags)0,                  // VkPipelineColorBlendStateCreateFlags flags;
259         VK_FALSE,                                                 // VkBool32 logicOpEnable;
260         VK_LOGIC_OP_COPY,                                         // VkLogicOp logicOp;
261         1u,                                                       // uint32_t attachmentCount;
262         &pipelineColorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
263         {0.0f, 0.0f, 0.0f, 0.0f},           // float blendConstants[4];
264     };
265 
266     const VkPipelineShaderStageCreateInfo pShaderStages[] = {
267         {
268             VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
269             DE_NULL,                                             // const void* pNext;
270             (VkPipelineShaderStageCreateFlags)0,                 // VkPipelineShaderStageCreateFlags flags;
271             VK_SHADER_STAGE_VERTEX_BIT,                          // VkShaderStageFlagBits stage;
272             vertexModule,                                        // VkShaderModule module;
273             "main",                                              // const char* pName;
274             DE_NULL,                                             // const VkSpecializationInfo* pSpecializationInfo;
275         },
276         {
277             VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
278             DE_NULL,                                             // const void* pNext;
279             (VkPipelineShaderStageCreateFlags)0,                 // VkPipelineShaderStageCreateFlags flags;
280             VK_SHADER_STAGE_FRAGMENT_BIT,                        // VkShaderStageFlagBits stage;
281             fragmentModule,                                      // VkShaderModule module;
282             "main",                                              // const char* pName;
283             DE_NULL,                                             // const VkSpecializationInfo* pSpecializationInfo;
284         },
285     };
286 
287     const VkPipelineDiscardRectangleStateCreateInfoEXT discardRectangleStateCreateInfo =
288         makeDiscardRectangleStateCreateInfo(dynamicDiscardRectangle, discardRectangleMode, discardRectangleCount,
289                                             pDiscardRectangles);
290 
291     const VkDynamicState dynamicStateDiscardRectangles = VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT;
292     const VkDynamicState dynamicStateScissor           = VK_DYNAMIC_STATE_SCISSOR;
293     std::vector<VkDynamicState> dynamicStates;
294 
295     if (dynamicDiscardRectangle)
296         dynamicStates.push_back(dynamicStateDiscardRectangles);
297     if (scissorMode == TEST_SCISSOR_MODE_DYNAMIC)
298         dynamicStates.push_back(dynamicStateScissor);
299 
300     const VkPipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo = {
301         VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
302         DE_NULL,                                              // const void* pNext;
303         0u,                                                   // VkPipelineDynamicStateCreateFlags flags;
304         (uint32_t)dynamicStates.size(),                       // uint32_t dynamicStateCount;
305         dynamicStates.data()                                  // const VkDynamicState* pDynamicStates;
306     };
307 
308     VkGraphicsPipelineCreateInfo graphicsPipelineInfo = {
309         VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType;
310         &discardRectangleStateCreateInfo,                // const void* pNext;
311         (VkPipelineCreateFlags)0,                        // VkPipelineCreateFlags flags;
312         2u,                                              // uint32_t stageCount;
313         pShaderStages,                                   // const VkPipelineShaderStageCreateInfo* pStages;
314         &vertexInputStateInfo,           // const VkPipelineVertexInputStateCreateInfo* pVertexInputState;
315         &pipelineInputAssemblyStateInfo, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState;
316         DE_NULL,                         // const VkPipelineTessellationStateCreateInfo* pTessellationState;
317         &pipelineViewportStateInfo,      // const VkPipelineViewportStateCreateInfo* pViewportState;
318         &pipelineRasterizationStateInfo, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState;
319         &pipelineMultisampleStateInfo,   // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
320         &pipelineDepthStencilStateInfo,  // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState;
321         &pipelineColorBlendStateInfo,    // const VkPipelineColorBlendStateCreateInfo* pColorBlendState;
322         &pipelineDynamicStateCreateInfo, // const VkPipelineDynamicStateCreateInfo* pDynamicState;
323         pipelineLayout,                  // VkPipelineLayout layout;
324         renderPass,                      // VkRenderPass renderPass;
325         0u,                              // uint32_t subpass;
326         DE_NULL,                         // VkPipeline basePipelineHandle;
327         0,                               // int32_t basePipelineIndex;
328     };
329 
330 #ifndef CTS_USES_VULKANSC
331     VkFormat colorAttachmentFormat = VK_FORMAT_R8G8B8A8_UNORM;
332     vk::VkPipelineRenderingCreateInfoKHR renderingCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR,
333                                                              &discardRectangleStateCreateInfo,
334                                                              0u,
335                                                              1u,
336                                                              &colorAttachmentFormat,
337                                                              VK_FORMAT_UNDEFINED,
338                                                              VK_FORMAT_UNDEFINED};
339 
340     // when pipeline is created without render pass we are using dynamic rendering
341     if (renderPass == DE_NULL)
342         graphicsPipelineInfo.pNext = &renderingCreateInfo;
343 #endif // CTS_USES_VULKANSC
344 
345     return createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineInfo);
346 }
347 
generateDiscardRectangles(const UVec2 & renderSize,uint32_t numRect,std::vector<VkRect2D> & rectangles)348 void generateDiscardRectangles(const UVec2 &renderSize, uint32_t numRect, std::vector<VkRect2D> &rectangles)
349 {
350     uint32_t cellHight = renderSize.y() - 10;
351     uint32_t cellWidth = (renderSize.x() - 10) / (2 * numRect - 1);
352 
353     DE_ASSERT(rectangles.size() == 0);
354 
355     for (uint32_t i = 0; i < numRect; i++)
356     {
357         VkRect2D rect;
358         rect.extent.height = cellHight;
359         rect.extent.width  = cellWidth;
360         rect.offset.x      = 5u + i * 2 * cellWidth;
361         rect.offset.y      = 5u;
362         rectangles.push_back(rect);
363     }
364 }
365 
366 //! Renders a colorful grid of rectangles.
generateReferenceImage(const tcu::TextureFormat format,const UVec2 & renderSize,const TestMode testMode,const Vec4 & color,const uint32_t numRectangles,const std::vector<VkRect2D> rectangles,const bool enableScissor,const VkRect2D scissor)367 tcu::TextureLevel generateReferenceImage(const tcu::TextureFormat format, const UVec2 &renderSize,
368                                          const TestMode testMode, const Vec4 &color, const uint32_t numRectangles,
369                                          const std::vector<VkRect2D> rectangles, const bool enableScissor,
370                                          const VkRect2D scissor)
371 {
372     tcu::TextureLevel image(format, renderSize.x(), renderSize.y());
373     const Vec4 rectColor  = testMode == TEST_MODE_INCLUSIVE ? Vec4(0.0f, 1.0f, 0.0f, 1.0f) : color;
374     const Vec4 clearColor = testMode == TEST_MODE_INCLUSIVE ? color : Vec4(0.0f, 1.0f, 0.0f, 1.0f);
375 
376     if (!enableScissor)
377     {
378         // Clear the image with clearColor
379         tcu::clear(image.getAccess(), clearColor);
380 
381         // Now draw the discard rectangles taking into account the selected mode.
382         for (uint32_t i = 0; i < numRectangles; i++)
383         {
384             tcu::clear(tcu::getSubregion(image.getAccess(), rectangles[i].offset.x, rectangles[i].offset.y,
385                                          rectangles[i].extent.width, rectangles[i].extent.height),
386                        rectColor);
387         }
388     }
389     else
390     {
391         // Clear the image with the original clear color
392         tcu::clear(image.getAccess(), color);
393         // Clear the scissor are with the clearColor which depends on the selected mode
394         tcu::clear(tcu::getSubregion(image.getAccess(), scissor.offset.x, scissor.offset.y, scissor.extent.width,
395                                      scissor.extent.height),
396                    clearColor);
397 
398         // Now draw the discard rectangles taking into account both the scissor area and
399         // the selected mode.
400         for (uint32_t rect = 0; rect < numRectangles; rect++)
401         {
402             for (uint32_t x = rectangles[rect].offset.x;
403                  x < (rectangles[rect].offset.x + rectangles[rect].extent.width); x++)
404             {
405                 for (uint32_t y = rectangles[rect].offset.y;
406                      y < (rectangles[rect].offset.y + rectangles[rect].extent.height); y++)
407                 {
408                     if ((x >= (uint32_t)scissor.offset.x) && (x < (scissor.offset.x + scissor.extent.width)) &&
409                         (y >= (uint32_t)scissor.offset.y) && (y < (scissor.offset.y + scissor.extent.height)))
410                     {
411                         image.getAccess().setPixel(rectColor, x, y);
412                     }
413                 }
414             }
415         }
416     }
417     return image;
418 }
419 
420 class DiscardRectanglesTestInstance : public TestInstance
421 {
422 public:
423     DiscardRectanglesTestInstance(Context &context, TestParams params);
~DiscardRectanglesTestInstance(void)424     virtual ~DiscardRectanglesTestInstance(void)
425     {
426     }
427     virtual tcu::TestStatus iterate(void);
428 
429 protected:
430     void preRenderCommands(VkCommandBuffer cmdBuffer) const;
431     void drawCommands(VkCommandBuffer cmdBuffer, const VkRect2D &rectScissor) const;
432 
433 #ifndef CTS_USES_VULKANSC
434     void beginSecondaryCmdBuffer(VkCommandBuffer cmdBuffer, VkFormat colorFormat,
435                                  VkRenderingFlagsKHR renderingFlags = 0u) const;
436 #endif // CTS_USES_VULKANSC
437 
438 private:
439     const TestParams m_params;
440     const Vec4 m_clearColor;
441     const UVec2 m_renderSize;
442     std::vector<Vec4> m_vertices;
443     std::vector<VkRect2D> m_rectangles;
444 
445     Move<VkImage> m_colorImage;
446     MovePtr<Allocation> m_colorImageAlloc;
447     Move<VkImageView> m_colorAttachment;
448     SharedPtr<Buffer> m_colorBuffer;
449     SharedPtr<Buffer> m_vertexBuffer;
450     Move<VkShaderModule> m_vertexModule;
451     Move<VkShaderModule> m_fragmentModule;
452     Move<VkRenderPass> m_renderPass;
453     Move<VkFramebuffer> m_framebuffer;
454     Move<VkPipelineLayout> m_pipelineLayout;
455     Move<VkPipeline> m_pipeline;
456     Move<VkCommandPool> m_cmdPool;
457     Move<VkCommandBuffer> m_cmdBuffer;
458     Move<VkCommandBuffer> m_secCmdBuffer;
459 };
460 
DiscardRectanglesTestInstance(Context & context,TestParams params)461 DiscardRectanglesTestInstance::DiscardRectanglesTestInstance(Context &context, TestParams params)
462     : TestInstance(context)
463     , m_params(params)
464     , m_clearColor(Vec4(1.0f, 0.0f, 0.0f, 1.0f))
465     , m_renderSize(UVec2(340, 100))
466 {
467 }
468 
iterate(void)469 tcu::TestStatus DiscardRectanglesTestInstance::iterate(void)
470 {
471     const DeviceInterface &vk                            = m_context.getDeviceInterface();
472     const InstanceInterface &vki                         = m_context.getInstanceInterface();
473     const VkPhysicalDevice physicalDevice                = m_context.getPhysicalDevice();
474     const VkDevice device                                = m_context.getDevice();
475     const VkQueue queue                                  = m_context.getUniversalQueue();
476     const uint32_t queueFamilyIndex                      = m_context.getUniversalQueueFamilyIndex();
477     Allocator &allocator                                 = m_context.getDefaultAllocator();
478     const VkDiscardRectangleModeEXT discardRectangleMode = m_params.testMode == TEST_MODE_EXCLUSIVE ?
479                                                                VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT :
480                                                                VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT;
481     const VkRect2D rectScissor                           = {{90, 25}, {160, 50}};
482     const VkImageSubresourceRange colorSubresourceRange =
483         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
484     const VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM;
485     const VkDeviceSize colorBufferSize =
486         m_renderSize.x() * m_renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
487 
488     // Check for VK_EXT_discard_rectangles support and maximum number of active discard rectangles
489     {
490         VkPhysicalDeviceDiscardRectanglePropertiesEXT discardRectangleProperties;
491         deMemset(&discardRectangleProperties, 0, sizeof(VkPhysicalDeviceDiscardRectanglePropertiesEXT));
492         discardRectangleProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT;
493 
494         VkPhysicalDeviceProperties2 physicalDeviceProperties;
495         physicalDeviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
496         physicalDeviceProperties.pNext = &discardRectangleProperties;
497 
498         vki.getPhysicalDeviceProperties2(physicalDevice, &physicalDeviceProperties);
499 
500         if (discardRectangleProperties.maxDiscardRectangles == 0)
501         {
502             throw tcu::NotSupportedError("Implementation doesn't support discard rectangles");
503         }
504 
505         if (discardRectangleProperties.maxDiscardRectangles < 4)
506         {
507             std::ostringstream message;
508             message << "Implementation doesn't support the minimum value for maxDiscardRectangles: "
509                     << discardRectangleProperties.maxDiscardRectangles << " < 4";
510             return tcu::TestStatus::fail(message.str());
511         }
512 
513         if (discardRectangleProperties.maxDiscardRectangles < m_params.numRectangles)
514         {
515             std::ostringstream message;
516             message << "Implementation doesn't support the required number of discard rectangles: "
517                     << discardRectangleProperties.maxDiscardRectangles << " < " << m_params.numRectangles;
518             throw tcu::NotSupportedError(message.str());
519         }
520     }
521 
522     // Color attachment
523     {
524         m_colorImage =
525             makeImage(vk, device,
526                       makeImageCreateInfo(colorFormat, m_renderSize,
527                                           VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT));
528         m_colorImageAlloc = bindImage(vk, device, allocator, *m_colorImage, MemoryRequirement::Any);
529         m_colorBuffer =
530             Buffer::createAndAlloc(vk, device, makeBufferCreateInfo(colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT),
531                                    allocator, MemoryRequirement::HostVisible);
532         m_colorAttachment =
533             makeImageView(vk, device, *m_colorImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSubresourceRange);
534 
535         // Zero colorBuffer.
536         const Allocation alloc = m_colorBuffer->getBoundMemory();
537         deMemset(alloc.getHostPtr(), 0, static_cast<std::size_t>(colorBufferSize));
538         flushAlloc(vk, device, alloc);
539     }
540 
541     // Initialize the pipeline and other variables
542     {
543         // Draw a quad covering the whole framebuffer
544         m_vertices.push_back(Vec4(-1.0f, 1.0f, 0.0f, 1.0f));
545         m_vertices.push_back(Vec4(-1.0f, -1.0f, 0.0f, 1.0f));
546         m_vertices.push_back(Vec4(1.0f, 1.0f, 0.0f, 1.0f));
547         m_vertices.push_back(Vec4(1.0f, -1.0f, 0.0f, 1.0f));
548         VkDeviceSize vertexBufferSize = sizeInBytes(m_vertices);
549         m_vertexBuffer                = Buffer::createAndAlloc(
550             vk, device, makeBufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), allocator,
551             MemoryRequirement::HostVisible);
552 
553         deMemcpy(m_vertexBuffer->getBoundMemory().getHostPtr(), m_vertices.data(),
554                  static_cast<std::size_t>(vertexBufferSize));
555         flushAlloc(vk, device, m_vertexBuffer->getBoundMemory());
556 
557         m_vertexModule   = createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u);
558         m_fragmentModule = createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0u);
559 
560         if (!m_params.groupParams->useDynamicRendering)
561         {
562             m_renderPass = makeRenderPass(vk, device, colorFormat);
563             m_framebuffer =
564                 makeFramebuffer(vk, device, *m_renderPass, m_colorAttachment.get(),
565                                 static_cast<uint32_t>(m_renderSize.x()), static_cast<uint32_t>(m_renderSize.y()));
566         }
567 
568         m_pipelineLayout = makePipelineLayout(vk, device);
569 
570         generateDiscardRectangles(m_renderSize, m_params.numRectangles, m_rectangles);
571         m_pipeline =
572             makeGraphicsPipeline(vk, device, *m_pipelineLayout, *m_renderPass, *m_vertexModule, *m_fragmentModule,
573                                  m_renderSize, m_params.dynamicDiscardRectangles, discardRectangleMode,
574                                  m_params.numRectangles, m_rectangles.data(), m_params.scissorMode, rectScissor);
575         m_cmdPool   = createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
576         m_cmdBuffer = allocateCommandBuffer(vk, device, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
577     }
578 
579     const VkClearValue clearValue = makeClearValueColor(m_clearColor);
580     const VkRect2D renderArea{
581         makeOffset2D(0, 0),
582         makeExtent2D(m_renderSize.x(), m_renderSize.y()),
583     };
584 
585     // Write command buffers and submit it
586 
587 #ifndef CTS_USES_VULKANSC
588     if (m_params.groupParams->useSecondaryCmdBuffer)
589     {
590         m_secCmdBuffer = allocateCommandBuffer(vk, device, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
591 
592         // record secondary command buffer
593         if (m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
594         {
595             beginSecondaryCmdBuffer(*m_secCmdBuffer, colorFormat, VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
596             beginRendering(vk, *m_secCmdBuffer, *m_colorAttachment, renderArea, clearValue,
597                            VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ATTACHMENT_LOAD_OP_CLEAR);
598         }
599         else
600             beginSecondaryCmdBuffer(*m_secCmdBuffer, colorFormat);
601 
602         drawCommands(*m_secCmdBuffer, rectScissor);
603 
604         if (m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
605             vk.cmdEndRendering(*m_secCmdBuffer);
606 
607         endCommandBuffer(vk, *m_secCmdBuffer);
608 
609         // record primary command buffer
610         beginCommandBuffer(vk, *m_cmdBuffer, 0u);
611         preRenderCommands(*m_cmdBuffer);
612 
613         if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
614             beginRendering(vk, *m_cmdBuffer, *m_colorAttachment, renderArea, clearValue,
615                            VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ATTACHMENT_LOAD_OP_CLEAR,
616                            VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
617 
618         vk.cmdExecuteCommands(*m_cmdBuffer, 1u, &*m_secCmdBuffer);
619 
620         if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
621             vk.cmdEndRendering(*m_cmdBuffer);
622     }
623     else if (m_params.groupParams->useDynamicRendering)
624     {
625         beginCommandBuffer(vk, *m_cmdBuffer);
626 
627         preRenderCommands(*m_cmdBuffer);
628         beginRendering(vk, *m_cmdBuffer, *m_colorAttachment, renderArea, clearValue,
629                        VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ATTACHMENT_LOAD_OP_CLEAR);
630         drawCommands(*m_cmdBuffer, rectScissor);
631         vk.cmdEndRendering(*m_cmdBuffer);
632     }
633 #endif // CTS_USES_VULKANSC
634 
635     if (!m_params.groupParams->useDynamicRendering)
636     {
637         const VkRenderPassBeginInfo renderPassBeginInfo{
638             VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType;
639             DE_NULL,                                  // const void* pNext;
640             *m_renderPass,                            // VkRenderPass renderPass;
641             *m_framebuffer,                           // VkFramebuffer framebuffer;
642             renderArea,                               // VkRect2D renderArea;
643             1u,                                       // uint32_t clearValueCount;
644             &clearValue,                              // const VkClearValue* pClearValues;
645         };
646 
647         beginCommandBuffer(vk, *m_cmdBuffer);
648 
649         preRenderCommands(*m_cmdBuffer);
650         vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
651         drawCommands(*m_cmdBuffer, rectScissor);
652         vk.cmdEndRenderPass(*m_cmdBuffer);
653     }
654 
655     copyImageToBuffer(vk, *m_cmdBuffer, *m_colorImage, m_colorBuffer->object(),
656                       tcu::IVec2(m_renderSize.x(), m_renderSize.y()), VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
657                       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, colorSubresourceRange.layerCount);
658     VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer));
659 
660     submitCommandsAndWait(vk, device, queue, *m_cmdBuffer);
661 
662     // Verify results
663     {
664         const Allocation alloc = m_colorBuffer->getBoundMemory();
665         invalidateAlloc(vk, device, alloc);
666 
667         const tcu::ConstPixelBufferAccess resultImage(mapVkFormat(colorFormat), m_renderSize.x(), m_renderSize.y(), 1u,
668                                                       alloc.getHostPtr());
669         const tcu::TextureLevel referenceImage = generateReferenceImage(
670             mapVkFormat(colorFormat), m_renderSize, m_params.testMode, m_clearColor, m_params.numRectangles,
671             m_rectangles, m_params.scissorMode != TEST_SCISSOR_MODE_NONE, rectScissor);
672         if (!tcu::floatThresholdCompare(m_context.getTestContext().getLog(), "Compare", "Result comparison",
673                                         referenceImage.getAccess(), resultImage, Vec4(0.02f), tcu::COMPARE_LOG_RESULT))
674             TCU_FAIL("Rendered image is not correct");
675     }
676     return tcu::TestStatus::pass("OK");
677 }
678 
preRenderCommands(vk::VkCommandBuffer cmdBuffer) const679 void DiscardRectanglesTestInstance::preRenderCommands(vk::VkCommandBuffer cmdBuffer) const
680 {
681     if (!m_params.groupParams->useDynamicRendering)
682         return;
683 
684     const DeviceInterface &vk = m_context.getDeviceInterface();
685     initialTransitionColor2DImage(vk, cmdBuffer, *m_colorImage, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
686                                   VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
687 }
688 
drawCommands(vk::VkCommandBuffer cmdBuffer,const VkRect2D & rectScissor) const689 void DiscardRectanglesTestInstance::drawCommands(vk::VkCommandBuffer cmdBuffer, const VkRect2D &rectScissor) const
690 {
691     const DeviceInterface &vk = m_context.getDeviceInterface();
692     vk.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
693     {
694         const VkBuffer vertexBuffer           = m_vertexBuffer->object();
695         const VkDeviceSize vertexBufferOffset = 0ull;
696         vk.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer, &vertexBufferOffset);
697     }
698     if (m_params.dynamicDiscardRectangles)
699     {
700         vk.cmdSetDiscardRectangleEXT(cmdBuffer, 0u, m_params.numRectangles, m_rectangles.data());
701     }
702     if (m_params.scissorMode == TEST_SCISSOR_MODE_DYNAMIC)
703     {
704         vk.cmdSetScissor(cmdBuffer, 0u, 1u, &rectScissor);
705     }
706     vk.cmdDraw(cmdBuffer, static_cast<uint32_t>(m_vertices.size()), 1u, 0u, 0u); // two triangles
707 }
708 
709 #ifndef CTS_USES_VULKANSC
beginSecondaryCmdBuffer(VkCommandBuffer cmdBuffer,VkFormat colorFormat,VkRenderingFlagsKHR renderingFlags) const710 void DiscardRectanglesTestInstance::beginSecondaryCmdBuffer(VkCommandBuffer cmdBuffer, VkFormat colorFormat,
711                                                             VkRenderingFlagsKHR renderingFlags) const
712 {
713     VkCommandBufferInheritanceRenderingInfoKHR inheritanceRenderingInfo{
714         VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR, // VkStructureType sType;
715         DE_NULL,                                                         // const void* pNext;
716         renderingFlags,                                                  // VkRenderingFlagsKHR flags;
717         0u,                                                              // uint32_t viewMask;
718         1u,                                                              // uint32_t colorAttachmentCount;
719         &colorFormat,                                                    // const VkFormat* pColorAttachmentFormats;
720         VK_FORMAT_UNDEFINED,                                             // VkFormat depthAttachmentFormat;
721         VK_FORMAT_UNDEFINED,                                             // VkFormat stencilAttachmentFormat;
722         VK_SAMPLE_COUNT_1_BIT,                                           // VkSampleCountFlagBits rasterizationSamples;
723     };
724     const VkCommandBufferInheritanceInfo bufferInheritanceInfo = initVulkanStructure(&inheritanceRenderingInfo);
725 
726     VkCommandBufferUsageFlags usageFlags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
727     if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
728         usageFlags |= VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
729 
730     const VkCommandBufferBeginInfo commandBufBeginParams{
731         VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
732         DE_NULL,                                     // const void* pNext;
733         usageFlags,                                  // VkCommandBufferUsageFlags flags;
734         &bufferInheritanceInfo};
735 
736     const DeviceInterface &vk = m_context.getDeviceInterface();
737     VK_CHECK(vk.beginCommandBuffer(cmdBuffer, &commandBufBeginParams));
738 }
739 #endif // CTS_USES_VULKANSC
740 
741 class DiscardRectanglesTestCase : public TestCase
742 {
743 public:
744     DiscardRectanglesTestCase(tcu::TestContext &context, const char *name, TestParams params);
~DiscardRectanglesTestCase(void)745     virtual ~DiscardRectanglesTestCase(void)
746     {
747     }
748 
749     virtual TestInstance *createInstance(Context &context) const;
750     virtual void initPrograms(SourceCollections &programCollection) const;
751     virtual void checkSupport(Context &context) const;
752 
753 private:
754     const TestParams m_params;
755 };
756 
DiscardRectanglesTestCase(tcu::TestContext & context,const char * name,TestParams params)757 DiscardRectanglesTestCase::DiscardRectanglesTestCase(tcu::TestContext &context, const char *name, TestParams params)
758     : TestCase(context, name)
759     , m_params(params)
760 {
761 }
762 
initPrograms(SourceCollections & programCollection) const763 void DiscardRectanglesTestCase::initPrograms(SourceCollections &programCollection) const
764 {
765     // Vertex
766     {
767         std::ostringstream src;
768         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
769             << "\n"
770             << "layout(location = 0) in highp vec4 position;\n"
771             << "layout(location = 0) out highp vec4 vsColor;\n"
772             << "\n"
773             << "out gl_PerVertex {\n"
774             << "   vec4 gl_Position;\n"
775             << "};\n"
776             << "\n"
777             << "void main (void)\n"
778             << "{\n"
779             << "    gl_Position = position;\n"
780             << "    vsColor     = vec4(0.0f, 1.0f, 0.0f, 1.0f);\n"
781             << "}\n";
782         programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
783     }
784 
785     // Fragment
786     {
787         std::ostringstream src;
788         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
789             << "\n"
790             << "layout(location = 0) in highp vec4 vsColor;\n"
791             << "layout(location = 0) out highp vec4 fsColor;\n"
792             << "\n"
793             << "void main (void)\n"
794             << "{\n"
795             << "    fsColor     = vsColor;\n"
796             << "}\n";
797         programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
798     }
799 }
800 
checkSupport(Context & context) const801 void DiscardRectanglesTestCase::checkSupport(Context &context) const
802 {
803     context.requireDeviceFunctionality("VK_EXT_discard_rectangles");
804     if (m_params.groupParams->useDynamicRendering)
805         context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
806 }
807 
createInstance(Context & context) const808 TestInstance *DiscardRectanglesTestCase::createInstance(Context &context) const
809 {
810     return new DiscardRectanglesTestInstance(context, m_params);
811 }
812 
createTests(tcu::TestCaseGroup * testGroup,const SharedGroupParams groupParams)813 void createTests(tcu::TestCaseGroup *testGroup, const SharedGroupParams groupParams)
814 {
815     tcu::TestContext &testCtx                               = testGroup->getTestContext();
816     uint32_t numRect[NUM_RECT_TESTS]                        = {1, 2, 3, 4, 8, 16};
817     std::string modeName[TEST_MODE_COUNT]                   = {"inclusive_", "exclusive_"};
818     std::string scissorName[TEST_SCISSOR_MODE_COUNT]        = {"", "scissor_", "dynamic_scissor_"};
819     std::string dynamicName[NUM_DYNAMIC_DISCARD_TYPE_TESTS] = {"", "dynamic_discard_"};
820 
821     for (uint32_t dynamic = 0; dynamic < NUM_DYNAMIC_DISCARD_TYPE_TESTS; dynamic++)
822     {
823         for (uint32_t scissor = 0; scissor < TEST_SCISSOR_MODE_COUNT; scissor++)
824         {
825             for (uint32_t mode = 0; mode < TEST_MODE_COUNT; mode++)
826             {
827                 for (uint32_t rect = 0; rect < NUM_RECT_TESTS; rect++)
828                 {
829                     std::ostringstream name;
830                     TestParams params{
831                         (TestMode)mode,           // TestMode testMode;
832                         numRect[rect],            // uint32_t numRectangles;
833                         dynamic ? true : false,   // bool dynamicDiscardRectangles;
834                         (TestScissorMode)scissor, // TestScissorMode scissorMode;
835                         groupParams,              // const SharedGroupParams groupParams;
836                     };
837 
838                     name << dynamicName[dynamic] << scissorName[scissor] << modeName[mode] << "rect_" << numRect[rect];
839 
840                     testGroup->addChild(new DiscardRectanglesTestCase(testCtx, name.str().c_str(), params));
841                 }
842             }
843         }
844     }
845 }
846 } // namespace
847 
createDiscardRectanglesTests(tcu::TestContext & testCtx,const SharedGroupParams groupParams)848 tcu::TestCaseGroup *createDiscardRectanglesTests(tcu::TestContext &testCtx, const SharedGroupParams groupParams)
849 {
850     return createTestGroup(testCtx, "discard_rectangles", createTests, groupParams);
851 }
852 
853 } // namespace Draw
854 } // namespace vkt
855