xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/draw/vktDrawScissorTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2019 Google Inc.
6  * Copyright (c) 2019 The Khronos Group Inc.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Scissoring tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktDrawScissorTests.hpp"
26 
27 #include "vktDrawBaseClass.hpp"
28 #include "vkQueryUtil.hpp"
29 #include "vkCmdUtil.hpp"
30 #include "vkTypeUtil.hpp"
31 #include "vktTestGroupUtil.hpp"
32 
33 #include "tcuTestCase.hpp"
34 #include "tcuTextureUtil.hpp"
35 #include "tcuImageCompare.hpp"
36 
37 #include <string>
38 
39 namespace vkt
40 {
41 namespace Draw
42 {
43 namespace
44 {
45 using namespace vk;
46 using namespace std;
47 using namespace tcu;
48 
49 enum
50 {
51     WIDTH  = 256,
52     HEIGHT = 256
53 };
54 
55 struct ColorQuad
56 {
ColorQuadvkt::Draw::__anon4997828e0111::ColorQuad57     ColorQuad(uint32_t x, uint32_t y, uint32_t width, uint32_t height, Vec4 color)
58         : m_x(x)
59         , m_y(y)
60         , m_width(width)
61         , m_height(height)
62         , m_color(color)
63     {
64     }
65 
66     uint32_t m_x;
67     uint32_t m_y;
68     uint32_t m_width;
69     uint32_t m_height;
70     Vec4 m_color;
71 };
72 
scissorQuad(ColorQuad quad,VkRect2D scissor,VkExtent2D framebufferSize)73 ColorQuad scissorQuad(ColorQuad quad, VkRect2D scissor, VkExtent2D framebufferSize)
74 {
75     int left   = quad.m_x;
76     int right  = quad.m_x + quad.m_width;
77     int top    = quad.m_y;
78     int bottom = quad.m_y + quad.m_height;
79 
80     left   = de::max(left, scissor.offset.x);
81     left   = de::max(left, 0);
82     right  = de::min(right, scissor.offset.x + (int)scissor.extent.width);
83     right  = de::min(right, (int)framebufferSize.width);
84     top    = de::max(top, scissor.offset.y);
85     top    = de::max(top, 0);
86     bottom = de::min(bottom, scissor.offset.y + (int)scissor.extent.height);
87     bottom = de::min(bottom, (int)framebufferSize.height);
88 
89     return ColorQuad(left, top, de::max(right - left, 0), de::max(bottom - top, 0), quad.m_color);
90 }
91 
92 class TestCommand
93 {
94 public:
TestCommand(void)95     TestCommand(void)
96     {
97     }
~TestCommand(void)98     virtual ~TestCommand(void)
99     {
100     }
101 
getVertices(uint32_t offset)102     virtual vector<PositionColorVertex> getVertices(uint32_t offset)
103     {
104         DE_UNREF(offset);
105         return vector<PositionColorVertex>();
106     }
107     virtual void addCommands(const DeviceInterface &vk, VkCommandBuffer cmdBuffer) = 0;
getMaxScissor(void)108     virtual uint32_t getMaxScissor(void)
109     {
110         return 0;
111     }
getQuad(void)112     virtual vector<ColorQuad> getQuad(void)
113     {
114         return vector<ColorQuad>();
115     }
updateScissors(vector<VkRect2D> scissors)116     virtual vector<VkRect2D> updateScissors(vector<VkRect2D> scissors)
117     {
118         return scissors;
119     }
isScissored(void)120     virtual bool isScissored(void)
121     {
122         return false;
123     }
124 
125 private:
126 };
127 
128 typedef de::SharedPtr<TestCommand> TestCommandSp;
129 
130 class QuadDrawTestCommand : public TestCommand
131 {
132 public:
133     QuadDrawTestCommand(uint32_t x, uint32_t y, uint32_t width, uint32_t height, Vec4 color);
~QuadDrawTestCommand(void)134     virtual ~QuadDrawTestCommand(void)
135     {
136     }
137 
138     virtual vector<PositionColorVertex> getVertices(uint32_t offset);
139     virtual void addCommands(const DeviceInterface &vk, VkCommandBuffer cmdBuffer);
getQuad(void)140     virtual vector<ColorQuad> getQuad(void)
141     {
142         return vector<ColorQuad>(1, m_quad);
143     }
isScissored(void)144     virtual bool isScissored(void)
145     {
146         return true;
147     }
148 
149 private:
150     uint32_t m_offset;
151     ColorQuad m_quad;
152 };
153 
QuadDrawTestCommand(uint32_t x,uint32_t y,uint32_t width,uint32_t height,Vec4 color)154 QuadDrawTestCommand::QuadDrawTestCommand(uint32_t x, uint32_t y, uint32_t width, uint32_t height, Vec4 color)
155     : m_offset(0)
156     , m_quad(x, y, width, height, color)
157 {
158 }
159 
getVertices(uint32_t offset)160 vector<PositionColorVertex> QuadDrawTestCommand::getVertices(uint32_t offset)
161 {
162     vector<PositionColorVertex> vertices;
163     float scaleWidth  = 2.0f / (float)WIDTH;
164     float scaleHeight = 2.0f / (float)HEIGHT;
165     Vec4 topLeft(-1.0f + scaleWidth * (float)m_quad.m_x, -1.0f + scaleHeight * (float)m_quad.m_y, 0.0f, 1.0f);
166     Vec4 topRight(-1.0f + scaleWidth * (float)(m_quad.m_x + m_quad.m_width), -1.0f + scaleHeight * (float)m_quad.m_y,
167                   0.0f, 1.0f);
168     Vec4 bottomLeft(-1.0f + scaleWidth * (float)m_quad.m_x, -1.0f + scaleHeight * (float)(m_quad.m_y + m_quad.m_height),
169                     0.0f, 1.0f);
170     Vec4 bottomRight(-1.0f + scaleWidth * (float)(m_quad.m_x + m_quad.m_width),
171                      -1.0f + scaleHeight * (float)(m_quad.m_y + m_quad.m_height), 0.0f, 1.0f);
172 
173     m_offset = offset;
174 
175     vertices.push_back(PositionColorVertex(topLeft, m_quad.m_color));
176     vertices.push_back(PositionColorVertex(bottomRight, m_quad.m_color));
177     vertices.push_back(PositionColorVertex(bottomLeft, m_quad.m_color));
178     vertices.push_back(PositionColorVertex(topLeft, m_quad.m_color));
179     vertices.push_back(PositionColorVertex(topRight, m_quad.m_color));
180     vertices.push_back(PositionColorVertex(bottomRight, m_quad.m_color));
181 
182     return vertices;
183 }
184 
addCommands(const DeviceInterface & vk,VkCommandBuffer cmdBuffer)185 void QuadDrawTestCommand::addCommands(const DeviceInterface &vk, VkCommandBuffer cmdBuffer)
186 {
187     vk.cmdDraw(cmdBuffer, 6u, 1u, m_offset, 0u);
188 }
189 
190 class RectClearTestCommand : public TestCommand
191 {
192 public:
193     RectClearTestCommand(uint32_t x, uint32_t y, uint32_t width, uint32_t height, Vec4 color);
~RectClearTestCommand(void)194     virtual ~RectClearTestCommand(void)
195     {
196     }
197 
198     virtual void addCommands(const DeviceInterface &vk, VkCommandBuffer cmdBuffer);
getQuad(void)199     virtual vector<ColorQuad> getQuad(void)
200     {
201         return vector<ColorQuad>(1, m_quad);
202     }
203 
204 private:
205     ColorQuad m_quad;
206 };
207 
RectClearTestCommand(uint32_t x,uint32_t y,uint32_t width,uint32_t height,Vec4 color)208 RectClearTestCommand::RectClearTestCommand(uint32_t x, uint32_t y, uint32_t width, uint32_t height, Vec4 color)
209     : m_quad(x, y, width, height, color)
210 {
211 }
212 
addCommands(const DeviceInterface & vk,VkCommandBuffer cmdBuffer)213 void RectClearTestCommand::addCommands(const DeviceInterface &vk, VkCommandBuffer cmdBuffer)
214 {
215     const VkClearAttachment attachment = {
216         VK_IMAGE_ASPECT_COLOR_BIT,          // VkImageAspectFlags    aspectMask
217         0u,                                 // uint32_t                colorAttachment
218         makeClearValueColor(m_quad.m_color) // VkClearValue            clearValue
219     };
220 
221     const VkClearRect rect = {
222         makeRect2D(m_quad.m_x, m_quad.m_y, m_quad.m_width, m_quad.m_height), // VkRect2D    rect
223         0u,                                                                  // uint32_t    baseArrayLayer
224         1u                                                                   // uint32_t    layerCount
225     };
226 
227     vk.cmdClearAttachments(cmdBuffer, 1u, &attachment, 1u, &rect);
228 }
229 
230 class DynamicScissorTestCommand : public TestCommand
231 {
232 public:
233     DynamicScissorTestCommand(uint32_t firstScissor, vector<VkRect2D> scissors);
~DynamicScissorTestCommand(void)234     virtual ~DynamicScissorTestCommand(void)
235     {
236     }
237 
238     virtual void addCommands(const DeviceInterface &vk, VkCommandBuffer cmdBuffer);
getMaxScissor(void)239     virtual uint32_t getMaxScissor(void)
240     {
241         return m_firstScissor + (uint32_t)m_scissors.size();
242     }
243     virtual vector<VkRect2D> updateScissors(vector<VkRect2D> scissors);
244 
245 private:
246     uint32_t m_firstScissor;
247     vector<VkRect2D> m_scissors;
248 };
249 
DynamicScissorTestCommand(uint32_t firstScissor,vector<VkRect2D> scissors)250 DynamicScissorTestCommand::DynamicScissorTestCommand(uint32_t firstScissor, vector<VkRect2D> scissors)
251     : m_firstScissor(firstScissor)
252     , m_scissors(scissors)
253 {
254 }
255 
addCommands(const DeviceInterface & vk,VkCommandBuffer cmdBuffer)256 void DynamicScissorTestCommand::addCommands(const DeviceInterface &vk, VkCommandBuffer cmdBuffer)
257 {
258     vk.cmdSetScissor(cmdBuffer, m_firstScissor, (uint32_t)m_scissors.size(), m_scissors.data());
259 }
260 
updateScissors(vector<VkRect2D> scissors)261 vector<VkRect2D> DynamicScissorTestCommand::updateScissors(vector<VkRect2D> scissors)
262 {
263     for (size_t scissorIdx = 0; scissorIdx < m_scissors.size(); scissorIdx++)
264     {
265         while (scissors.size() <= m_firstScissor + scissorIdx)
266             scissors.push_back(makeRect2D(0, 0)); // Add empty scissor
267 
268         scissors[m_firstScissor + scissorIdx] = m_scissors[scissorIdx];
269     }
270 
271     return scissors;
272 }
273 
274 struct TestParams
275 {
TestParamsvkt::Draw::__anon4997828e0111::TestParams276     TestParams(const SharedGroupParams gp) : groupParams(gp), framebufferSize({WIDTH, HEIGHT})
277     {
278     }
279 
280     bool dynamicScissor;
281     vector<VkRect2D> staticScissors;
282     vector<TestCommandSp> commands;
283     bool usesMultipleScissors;
284     const SharedGroupParams groupParams;
285     VkExtent2D framebufferSize;
286 };
287 
countScissors(TestParams params)288 uint32_t countScissors(TestParams params)
289 {
290     if (params.dynamicScissor)
291     {
292         uint32_t numScissors = 0u;
293 
294         for (size_t commandIdx = 0; commandIdx < params.commands.size(); commandIdx++)
295             numScissors = de::max(numScissors, params.commands[commandIdx]->getMaxScissor());
296 
297         return numScissors;
298     }
299     else
300         return (uint32_t)params.staticScissors.size();
301 }
302 
303 class ScissorTestInstance : public TestInstance
304 {
305 public:
306     ScissorTestInstance(Context &context, const TestParams &params);
307     ~ScissorTestInstance(void);
308     TestStatus iterate(void);
309 
310 protected:
311     void drawCommands(VkCommandBuffer cmdBuffer, VkPipeline pipeline, VkBuffer vertexBuffer) const;
312     void postRenderCommands(VkCommandBuffer cmdBuffer, VkImage colorTargetImage) const;
313 
314 #ifndef CTS_USES_VULKANSC
315     void beginSecondaryCmdBuffer(VkCommandBuffer cmdBuffer, VkFormat colorAttachmentFormat,
316                                  VkRenderingFlagsKHR renderingFlags = 0u) const;
317 #endif // CTS_USES_VULKANSC
318 
319 private:
320     TestParams m_params;
321 };
322 
ScissorTestInstance(Context & context,const TestParams & params)323 ScissorTestInstance::ScissorTestInstance(Context &context, const TestParams &params)
324     : vkt::TestInstance(context)
325     , m_params(params)
326 {
327 }
328 
~ScissorTestInstance(void)329 ScissorTestInstance::~ScissorTestInstance(void)
330 {
331 }
332 
333 class ScissorTestCase : public TestCase
334 {
335 public:
336     ScissorTestCase(TestContext &context, const char *name, const TestParams params);
337     ~ScissorTestCase(void);
338     virtual void initPrograms(SourceCollections &programCollection) const;
339     virtual TestInstance *createInstance(Context &context) const;
340     virtual void checkSupport(Context &context) const;
341 
342 private:
343     TestParams m_params;
344 };
345 
ScissorTestCase(TestContext & context,const char * name,const TestParams params)346 ScissorTestCase::ScissorTestCase(TestContext &context, const char *name, const TestParams params)
347     : vkt::TestCase(context, name)
348     , m_params(params)
349 {
350     m_params.usesMultipleScissors = params.staticScissors.size() > 1;
351 
352     for (size_t commandIdx = 0; commandIdx < m_params.commands.size(); commandIdx++)
353         if (m_params.commands[commandIdx]->getMaxScissor() > 1)
354             m_params.usesMultipleScissors = true;
355 }
356 
~ScissorTestCase(void)357 ScissorTestCase::~ScissorTestCase(void)
358 {
359 }
360 
checkSupport(Context & context) const361 void ScissorTestCase::checkSupport(Context &context) const
362 {
363     if (m_params.groupParams->useDynamicRendering)
364         context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
365 
366     if (m_params.usesMultipleScissors)
367     {
368         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
369         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_MULTI_VIEWPORT);
370     }
371 }
372 
initPrograms(SourceCollections & programCollection) const373 void ScissorTestCase::initPrograms(SourceCollections &programCollection) const
374 {
375     programCollection.glslSources.add("vert") << glu::VertexSource("#version 430\n"
376                                                                    "layout(location = 0) in vec4 in_position;\n"
377                                                                    "layout(location = 1) in vec4 in_color;\n"
378                                                                    "layout(location = 0) out vec4 out_color;\n"
379                                                                    "void main()\n"
380                                                                    "{\n"
381                                                                    "    gl_Position  = in_position;\n"
382                                                                    "    out_color    = in_color;\n"
383                                                                    "}\n");
384 
385     // Geometry shader draws the same triangles to all viewports
386     string geomSource = string("#version 430\n"
387                                "layout(invocations = ") +
388                         de::toString(countScissors(m_params)) +
389                         ") in;\n"
390                         "layout(triangles) in;\n"
391                         "layout(triangle_strip, max_vertices = 3) out;\n"
392                         "layout(location = 0) in vec4 in_color[];\n"
393                         "layout(location = 0) out vec4 out_color;\n"
394                         "void main()\n"
395                         "{\n"
396                         "    for (int i = 0; i < gl_in.length(); i++)\n"
397                         "    {\n"
398                         "        gl_ViewportIndex = gl_InvocationID;\n"
399                         "        gl_Position      = gl_in[i].gl_Position;\n"
400                         "        out_color        = in_color[i];\n"
401                         "        EmitVertex();\n"
402                         "    }\n"
403                         "    EndPrimitive();\n"
404                         "}\n";
405 
406     programCollection.glslSources.add("geom") << glu::GeometrySource(geomSource);
407 
408     programCollection.glslSources.add("frag") << glu::FragmentSource("#version 430\n"
409                                                                      "layout(location = 0) in vec4 in_color;\n"
410                                                                      "layout(location = 0) out vec4 out_color;\n"
411                                                                      "void main()\n"
412                                                                      "{\n"
413                                                                      "    out_color = in_color;\n"
414                                                                      "}\n");
415 }
416 
createInstance(Context & context) const417 TestInstance *ScissorTestCase::createInstance(Context &context) const
418 {
419     return new ScissorTestInstance(context, m_params);
420 }
421 
iterate(void)422 TestStatus ScissorTestInstance::iterate(void)
423 {
424     ConstPixelBufferAccess frame;
425     VkFormat colorImageFormat = VK_FORMAT_R8G8B8A8_UNORM;
426     de::SharedPtr<Image> colorTargetImage;
427     TestLog &log              = m_context.getTestContext().getLog();
428     const DeviceInterface &vk = m_context.getDeviceInterface();
429     const VkDevice device     = m_context.getDevice();
430     const CmdPoolCreateInfo cmdPoolCreateInfo(m_context.getUniversalQueueFamilyIndex());
431     Move<VkCommandPool> cmdPool     = createCommandPool(vk, device, &cmdPoolCreateInfo);
432     Move<VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
433     Move<VkCommandBuffer> secCmdBuffer;
434     const Unique<VkShaderModule> vs(createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0));
435     Move<VkShaderModule> gs;
436     const Unique<VkShaderModule> fs(createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0));
437     const uint32_t numScissors    = countScissors(m_params);
438     VkDeviceSize vertexBufferSize = 0;
439     de::SharedPtr<Buffer> vertexBuffer;
440     Move<VkRenderPass> renderPass;
441     Move<VkImageView> colorTargetView;
442     Move<VkFramebuffer> framebuffer;
443     Move<VkPipeline> pipeline;
444     TextureLevel refImage;
445     VkExtent2D framebufferSize = m_params.framebufferSize;
446 
447     if (m_params.usesMultipleScissors)
448         gs = createShaderModule(vk, device, m_context.getBinaryCollection().get("geom"), 0);
449 
450     // Create color buffer image
451     {
452         const VkExtent3D targetImageExtent = {WIDTH, HEIGHT, 1};
453         const ImageCreateInfo targetImageCreateInfo(
454             VK_IMAGE_TYPE_2D, colorImageFormat, targetImageExtent, 1, 1, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_TILING_OPTIMAL,
455             VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
456         colorTargetImage = Image::createAndAlloc(vk, device, targetImageCreateInfo, m_context.getDefaultAllocator(),
457                                                  m_context.getUniversalQueueFamilyIndex());
458     }
459 
460     const ImageViewCreateInfo colorTargetViewInfo(colorTargetImage->object(), VK_IMAGE_VIEW_TYPE_2D, colorImageFormat);
461     colorTargetView = createImageView(vk, device, &colorTargetViewInfo);
462 
463     // Create render pass
464     if (!m_params.groupParams->useDynamicRendering)
465     {
466         RenderPassCreateInfo renderPassCreateInfo;
467         renderPassCreateInfo.addAttachment(AttachmentDescription(
468             colorImageFormat, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE,
469             VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_STORE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
470             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
471 
472         const VkAttachmentReference colorAttachmentRef = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
473         renderPassCreateInfo.addSubpass(SubpassDescription(VK_PIPELINE_BIND_POINT_GRAPHICS, 0, 0, DE_NULL, 1,
474                                                            &colorAttachmentRef, DE_NULL, AttachmentReference(), 0,
475                                                            DE_NULL));
476 
477         renderPass = createRenderPass(vk, device, &renderPassCreateInfo);
478 
479         // Create framebuffer
480         vector<VkImageView> colorAttachment{*colorTargetView};
481         const FramebufferCreateInfo framebufferCreateInfo(*renderPass, colorAttachment, framebufferSize.width,
482                                                           framebufferSize.height, 1);
483         framebuffer = createFramebuffer(vk, device, &framebufferCreateInfo);
484     }
485 
486     // Create vertex buffer
487     {
488         vector<PositionColorVertex> vertices;
489 
490         for (size_t commandIdx = 0; commandIdx < m_params.commands.size(); commandIdx++)
491         {
492             vector<PositionColorVertex> commandVertices =
493                 m_params.commands[commandIdx]->getVertices((uint32_t)vertices.size());
494             vertices.insert(vertices.end(), commandVertices.begin(), commandVertices.end());
495         }
496 
497         vertexBufferSize = vertices.size() * sizeof(PositionColorVertex);
498 
499         if (vertexBufferSize > 0)
500         {
501             vertexBuffer = Buffer::createAndAlloc(vk, device,
502                                                   BufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
503                                                   m_context.getDefaultAllocator(), MemoryRequirement::HostVisible);
504             uint8_t *ptr = reinterpret_cast<uint8_t *>(vertexBuffer->getBoundMemory().getHostPtr());
505 
506             deMemcpy(ptr, vertices.data(), static_cast<size_t>(vertexBufferSize));
507             flushMappedMemoryRange(vk, device, vertexBuffer->getBoundMemory().getMemory(),
508                                    vertexBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
509         }
510     }
511 
512     const PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
513     Move<VkPipelineLayout> pipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
514 
515     // Create pipeline
516     {
517         const PipelineCreateInfo::ColorBlendState::Attachment colorBlendState;
518 
519         const VkVertexInputBindingDescription vertexInputBindingDescription = {
520             0,                          // deUintre                binding
521             (uint32_t)sizeof(Vec4) * 2, // uint32_t                stride
522             VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputRate    inputRate
523         };
524         const VkViewport viewport = makeViewport(WIDTH, HEIGHT);
525 
526         const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] = {
527             {0u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, 0u},
528             {1u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, (uint32_t)(sizeof(float) * 4)}};
529 
530         PipelineCreateInfo::VertexInputState vertexInputState = PipelineCreateInfo::VertexInputState(
531             1, &vertexInputBindingDescription, 2, vertexInputAttributeDescriptions);
532 
533         PipelineCreateInfo pipelineCreateInfo(*pipelineLayout, *renderPass, 0, 0);
534         pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vs, "main", VK_SHADER_STAGE_VERTEX_BIT));
535         if (m_params.usesMultipleScissors)
536             pipelineCreateInfo.addShader(
537                 PipelineCreateInfo::PipelineShaderStage(*gs, "main", VK_SHADER_STAGE_GEOMETRY_BIT));
538         pipelineCreateInfo.addShader(
539             PipelineCreateInfo::PipelineShaderStage(*fs, "main", VK_SHADER_STAGE_FRAGMENT_BIT));
540         pipelineCreateInfo.addState(PipelineCreateInfo::VertexInputState(vertexInputState));
541         pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST));
542         pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState(1, &colorBlendState));
543         pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState());
544         pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState());
545         pipelineCreateInfo.addState(PipelineCreateInfo::MultiSampleState());
546 
547         if (m_params.dynamicScissor)
548         {
549             pipelineCreateInfo.addState(
550                 PipelineCreateInfo::DynamicState(vector<VkDynamicState>(1, VK_DYNAMIC_STATE_SCISSOR)));
551             pipelineCreateInfo.addState(
552                 PipelineCreateInfo::ViewportState(numScissors, vector<VkViewport>(numScissors, viewport),
553                                                   vector<VkRect2D>(numScissors, makeRect2D(0, 0))));
554         }
555         else
556         {
557             pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(
558                 numScissors, vector<VkViewport>(numScissors, viewport), m_params.staticScissors));
559         }
560 
561 #ifndef CTS_USES_VULKANSC
562         VkPipelineRenderingCreateInfoKHR renderingCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR,
563                                                              DE_NULL,
564                                                              0u,
565                                                              1u,
566                                                              &colorImageFormat,
567                                                              VK_FORMAT_UNDEFINED,
568                                                              VK_FORMAT_UNDEFINED};
569 
570         if (m_params.groupParams->useDynamicRendering)
571             pipelineCreateInfo.pNext = &renderingCreateInfo;
572 #endif // CTS_USES_VULKANSC
573 
574         pipeline = createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo);
575     }
576 
577     // Queue commands and read results.
578     {
579         const ImageSubresourceRange subresourceRange(VK_IMAGE_ASPECT_COLOR_BIT);
580         const VkOffset3D zeroOffset   = {0, 0, 0};
581         const tcu::Vec4 clearColor    = {0.0f, 0.0f, 0.0f, 1.0f};
582         const VkClearValue clearValue = makeClearValueColor(clearColor);
583         const VkBuffer vBuffer        = (vertexBufferSize > 0) ? vertexBuffer->object() : DE_NULL;
584         const VkRect2D renderArea     = makeRect2D(m_params.framebufferSize);
585 
586         // Unreference value for Vulkan SC
587         DE_UNREF(clearValue);
588 
589         clearColorImage(vk, device, m_context.getUniversalQueue(), m_context.getUniversalQueueFamilyIndex(),
590                         colorTargetImage->object(), clearColor, VK_IMAGE_LAYOUT_UNDEFINED,
591                         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u, 1u);
592 
593 #ifndef CTS_USES_VULKANSC
594         if (m_params.groupParams->useSecondaryCmdBuffer)
595         {
596             secCmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
597 
598             // record secondary command buffer
599             if (m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
600             {
601                 beginSecondaryCmdBuffer(*secCmdBuffer, colorImageFormat,
602                                         VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
603                 beginRendering(vk, *secCmdBuffer, *colorTargetView, renderArea, clearValue,
604                                VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ATTACHMENT_LOAD_OP_CLEAR);
605             }
606             else
607                 beginSecondaryCmdBuffer(*secCmdBuffer, colorImageFormat);
608 
609             drawCommands(*secCmdBuffer, *pipeline, vBuffer);
610 
611             if (m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
612                 endRendering(vk, *secCmdBuffer);
613 
614             endCommandBuffer(vk, *secCmdBuffer);
615 
616             // record primary command buffer
617             beginCommandBuffer(vk, *cmdBuffer, 0u);
618 
619             if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
620                 beginRendering(vk, *cmdBuffer, *colorTargetView, renderArea, clearValue,
621                                VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ATTACHMENT_LOAD_OP_CLEAR,
622                                VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
623 
624             vk.cmdExecuteCommands(*cmdBuffer, 1u, &*secCmdBuffer);
625 
626             if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
627                 endRendering(vk, *cmdBuffer);
628 
629             postRenderCommands(*cmdBuffer, colorTargetImage->object());
630             endCommandBuffer(vk, *cmdBuffer);
631         }
632         else if (m_params.groupParams->useDynamicRendering)
633         {
634             beginCommandBuffer(vk, *cmdBuffer);
635 
636             beginRendering(vk, *cmdBuffer, *colorTargetView, renderArea, clearValue,
637                            VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ATTACHMENT_LOAD_OP_CLEAR);
638             drawCommands(*cmdBuffer, *pipeline, vBuffer);
639             endRendering(vk, *cmdBuffer);
640             postRenderCommands(*cmdBuffer, colorTargetImage->object());
641 
642             endCommandBuffer(vk, *cmdBuffer);
643         }
644 #endif // CTS_USES_VULKANSC
645 
646         if (!m_params.groupParams->useDynamicRendering)
647         {
648             beginCommandBuffer(vk, *cmdBuffer);
649 
650             beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor);
651             drawCommands(*cmdBuffer, *pipeline, vBuffer);
652             endRenderPass(vk, *cmdBuffer);
653             postRenderCommands(*cmdBuffer, colorTargetImage->object());
654 
655             endCommandBuffer(vk, *cmdBuffer);
656         }
657 
658         submitCommandsAndWait(vk, device, m_context.getUniversalQueue(), cmdBuffer.get());
659 
660         frame = colorTargetImage->readSurface(m_context.getUniversalQueue(), m_context.getDefaultAllocator(),
661                                               VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, zeroOffset, WIDTH, HEIGHT,
662                                               VK_IMAGE_ASPECT_COLOR_BIT);
663     }
664 
665     // Generate reference
666     {
667         refImage.setStorage(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM), WIDTH, HEIGHT);
668         clear(refImage.getAccess(), Vec4(0.0f, 0.0f, 0.0f, 1.0f));
669 
670         vector<VkRect2D> scissors = m_params.staticScissors;
671 
672         for (size_t commandIdx = 0; commandIdx < m_params.commands.size(); commandIdx++)
673         {
674             scissors = m_params.commands[commandIdx]->updateScissors(scissors);
675 
676             vector<ColorQuad> quad = m_params.commands[commandIdx]->getQuad();
677 
678             if (quad.empty())
679                 continue;
680 
681             for (size_t scissorIdx = 0; scissorIdx < scissors.size(); scissorIdx++)
682             {
683                 ColorQuad scissoredQuad = m_params.commands[commandIdx]->isScissored() ?
684                                               scissorQuad(quad[0], scissors[scissorIdx], framebufferSize) :
685                                               quad[0];
686 
687                 if (scissoredQuad.m_width == 0 || scissoredQuad.m_height == 0)
688                     continue;
689 
690                 clear(getSubregion(refImage.getAccess(), scissoredQuad.m_x, scissoredQuad.m_y, 0, scissoredQuad.m_width,
691                                    scissoredQuad.m_height, 1),
692                       scissoredQuad.m_color);
693             }
694         }
695     }
696 
697     // Compare results
698     qpTestResult res = QP_TEST_RESULT_PASS;
699 
700     if (!intThresholdCompare(log, "Result", "Image comparison result", refImage.getAccess(), frame, UVec4(0),
701                              COMPARE_LOG_RESULT))
702         res = QP_TEST_RESULT_FAIL;
703 
704     return TestStatus(res, qpGetTestResultName(res));
705 }
706 
drawCommands(VkCommandBuffer cmdBuffer,VkPipeline pipeline,VkBuffer vertexBuffer) const707 void ScissorTestInstance::drawCommands(VkCommandBuffer cmdBuffer, VkPipeline pipeline, VkBuffer vertexBuffer) const
708 {
709     const DeviceInterface &vk             = m_context.getDeviceInterface();
710     const VkDeviceSize vertexBufferOffset = 0;
711 
712     if (vertexBuffer != DE_NULL)
713         vk.cmdBindVertexBuffers(cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
714     vk.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
715 
716     for (size_t commandIdx = 0; commandIdx < m_params.commands.size(); commandIdx++)
717         m_params.commands[commandIdx]->addCommands(vk, cmdBuffer);
718 }
719 
postRenderCommands(VkCommandBuffer cmdBuffer,VkImage colorTargetImage) const720 void ScissorTestInstance::postRenderCommands(VkCommandBuffer cmdBuffer, VkImage colorTargetImage) const
721 {
722     const DeviceInterface &vk = m_context.getDeviceInterface();
723     transition2DImage(vk, cmdBuffer, colorTargetImage, VK_IMAGE_ASPECT_COLOR_BIT,
724                       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
725                       VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
726                       VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
727 }
728 
729 #ifndef CTS_USES_VULKANSC
beginSecondaryCmdBuffer(VkCommandBuffer cmdBuffer,VkFormat colorAttachmentFormat,VkRenderingFlagsKHR renderingFlags) const730 void ScissorTestInstance::beginSecondaryCmdBuffer(VkCommandBuffer cmdBuffer, VkFormat colorAttachmentFormat,
731                                                   VkRenderingFlagsKHR renderingFlags) const
732 {
733     VkCommandBufferInheritanceRenderingInfoKHR inheritanceRenderingInfo{
734         VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR, // VkStructureType sType;
735         DE_NULL,                                                         // const void* pNext;
736         renderingFlags,                                                  // VkRenderingFlagsKHR flags;
737         0u,                                                              // uint32_t viewMask;
738         1u,                                                              // uint32_t colorAttachmentCount;
739         &colorAttachmentFormat,                                          // const VkFormat* pColorAttachmentFormats;
740         VK_FORMAT_UNDEFINED,                                             // VkFormat depthAttachmentFormat;
741         VK_FORMAT_UNDEFINED,                                             // VkFormat stencilAttachmentFormat;
742         VK_SAMPLE_COUNT_1_BIT,                                           // VkSampleCountFlagBits rasterizationSamples;
743     };
744     const VkCommandBufferInheritanceInfo bufferInheritanceInfo = initVulkanStructure(&inheritanceRenderingInfo);
745 
746     VkCommandBufferUsageFlags usageFlags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
747     if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
748         usageFlags |= VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
749 
750     const VkCommandBufferBeginInfo commandBufBeginParams{
751         VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
752         DE_NULL,                                     // const void* pNext;
753         usageFlags,                                  // VkCommandBufferUsageFlags flags;
754         &bufferInheritanceInfo};
755 
756     const DeviceInterface &vk = m_context.getDeviceInterface();
757     VK_CHECK(vk.beginCommandBuffer(cmdBuffer, &commandBufBeginParams));
758 }
759 #endif // CTS_USES_VULKANSC
760 
createTests(TestCaseGroup * testGroup,const SharedGroupParams groupParams)761 void createTests(TestCaseGroup *testGroup, const SharedGroupParams groupParams)
762 {
763     TestContext &testCtx = testGroup->getTestContext();
764     const Vec4 red(1.0f, 0.0f, 0.0f, 1.0f);
765     const Vec4 green(0.0f, 1.0f, 0.0f, 1.0f);
766     const Vec4 blue(0.0f, 0.0f, 1.0f, 1.0f);
767     const Vec4 yellow(1.0f, 1.0f, 0.0f, 1.0f);
768 
769     // Two quads with a single static scissor
770     {
771         TestParams params(groupParams);
772         params.dynamicScissor = false;
773         params.staticScissors.push_back(makeRect2D(30, 40, WIDTH - 60, HEIGHT - 80));
774         params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(10, 10, 50, 50, red)));
775         params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(WIDTH - 80, HEIGHT - 100, 30, 40, green)));
776 
777         testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_two_quads", params));
778     }
779 
780     // Two clears with a single static scissor
781     {
782         TestParams params(groupParams);
783         params.dynamicScissor = false;
784         params.staticScissors.push_back(makeRect2D(30, 40, WIDTH - 60, HEIGHT - 80));
785         params.commands.push_back(TestCommandSp(new RectClearTestCommand(10, 10, 50, 50, red)));
786         params.commands.push_back(TestCommandSp(new RectClearTestCommand(WIDTH - 80, HEIGHT - 100, 30, 40, green)));
787 
788         testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_two_clears", params));
789     }
790 
791     // One quad with two static scissors
792     {
793         TestParams params(groupParams);
794         params.dynamicScissor = false;
795         params.staticScissors.push_back(makeRect2D(30, 40, WIDTH - 60, HEIGHT - 70));
796         params.staticScissors.push_back(makeRect2D(40, 50, WIDTH - 60, HEIGHT - 70));
797         params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(10, 10, WIDTH - 10, HEIGHT - 10, red)));
798 
799         testGroup->addChild(new ScissorTestCase(testCtx, "two_static_scissors_one_quad", params));
800     }
801 
802     // Static scissor extending outside viewport
803     {
804         TestParams params(groupParams);
805         params.dynamicScissor = false;
806         params.staticScissors.push_back(makeRect2D(30, 40, WIDTH, HEIGHT));
807         params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH, HEIGHT + 30, green)));
808 
809         testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_partially_outside_viewport", params));
810     }
811 
812     // Static scissor completely outside viewport
813     {
814         TestParams params(groupParams);
815         params.dynamicScissor = false;
816         params.staticScissors.push_back(makeRect2D(WIDTH + 30, HEIGHT + 40, WIDTH, HEIGHT));
817         params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(100, 100, 20, 30, green)));
818 
819         testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_outside_viewport", params));
820     }
821 
822     // Static scissor outside viewport and touching right border of viewport
823     {
824         TestParams params(groupParams);
825         params.dynamicScissor = false;
826         params.staticScissors.push_back(makeRect2D(WIDTH, 0, WIDTH, HEIGHT));
827         params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(100, 100, 20, 30, green)));
828 
829         testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_viewport_border", params));
830     }
831 
832     // Static scissor with offset + extent equal to largest positive int32
833     {
834         TestParams params(groupParams);
835         params.dynamicScissor = false;
836         params.staticScissors.push_back(makeRect2D(100, 100, 0x7fffffff - 100, 0x7fffffff - 100));
837         params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH, HEIGHT, green)));
838 
839         testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_max_int32", params));
840     }
841 
842     // 16 static scissors (minimum number required when multiViewport supported)
843     {
844         TestParams params(groupParams);
845         params.dynamicScissor = false;
846 
847         for (uint32_t i = 0; i < 16; i++)
848             params.staticScissors.push_back(makeRect2D(10 + i * 3, 20 + i * 2, WIDTH / 2, HEIGHT / 2));
849 
850         params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(5, 6, WIDTH - 10, HEIGHT - 2, red)));
851 
852         testGroup->addChild(new ScissorTestCase(testCtx, "16_static_scissors", params));
853     }
854 
855     // Two quads with an empty scissor
856     {
857         TestParams params(groupParams);
858         params.dynamicScissor = false;
859         params.staticScissors.push_back(makeRect2D(0, 0, 0, 0));
860         params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(10, 10, 50, 50, red)));
861         params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(WIDTH - 80, HEIGHT - 100, 30, 40, green)));
862 
863         testGroup->addChild(new ScissorTestCase(testCtx, "empty_static_scissor", params));
864     }
865 
866     // Two quads with a single dynamic scissor
867     {
868         TestParams params(groupParams);
869         params.dynamicScissor = true;
870         params.commands.push_back(TestCommandSp(
871             new DynamicScissorTestCommand(0, vector<VkRect2D>(1, makeRect2D(30, 40, WIDTH - 60, HEIGHT - 80)))));
872         params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(10, 10, 50, 50, red)));
873         params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(WIDTH - 80, HEIGHT - 100, 30, 40, green)));
874 
875         testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_two_quads", params));
876     }
877 
878     // Empty scissor for the first draw
879     {
880         TestParams params(groupParams);
881         params.dynamicScissor = true;
882         params.commands.push_back(
883             TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, makeRect2D(0, 0, 0, 0)))));
884         params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(10, 10, 50, 50, red)));
885         params.commands.push_back(TestCommandSp(
886             new DynamicScissorTestCommand(0, vector<VkRect2D>(1, makeRect2D(30, 40, WIDTH - 60, HEIGHT - 80)))));
887         params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(WIDTH - 80, HEIGHT - 100, 30, 40, green)));
888 
889         testGroup->addChild(new ScissorTestCase(testCtx, "empty_dynamic_scissor_first_draw", params));
890     }
891 
892     // Two quads with three scissors updated in between
893     {
894         TestParams params(groupParams);
895         VkRect2D rect = makeRect2D(10, 20, WIDTH - 60, HEIGHT - 70);
896         vector<VkRect2D> scissors;
897 
898         params.dynamicScissor = true;
899 
900         scissors.push_back(rect);
901         rect.offset.x += 10;
902         rect.offset.y += 10;
903         scissors.push_back(rect);
904         rect.offset.x += 10;
905         rect.offset.y += 10;
906         scissors.push_back(rect);
907 
908         params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, scissors)));
909         params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(5, 7, WIDTH - 20, HEIGHT - 9, red)));
910 
911         for (size_t scissorIdx = 0; scissorIdx < scissors.size(); scissorIdx++)
912             scissors[scissorIdx].offset.x += 20;
913 
914         params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, scissors)));
915         params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(8, 12, WIDTH - 2, HEIGHT - 19, green)));
916 
917         testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_updates_between_draws", params));
918     }
919 
920     // Scissor updates out of order
921     {
922         TestParams params(groupParams);
923         VkRect2D rect = makeRect2D(10, 20, WIDTH - 60, HEIGHT - 70);
924         vector<VkRect2D> scissors;
925 
926         params.dynamicScissor = true;
927 
928         scissors.push_back(rect);
929         rect.offset.x += 10;
930         rect.offset.y += 10;
931         scissors.push_back(rect);
932         rect.offset.x += 10;
933         rect.offset.y += 10;
934         scissors.push_back(rect);
935 
936         params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(2, vector<VkRect2D>(1, scissors[2]))));
937         params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(1, vector<VkRect2D>(1, scissors[1]))));
938         params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, scissors[0]))));
939         params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(5, 7, WIDTH - 20, HEIGHT - 9, red)));
940 
941         for (size_t scissorIdx = 0; scissorIdx < scissors.size(); scissorIdx++)
942             scissors[scissorIdx].offset.x += 20;
943 
944         params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(1, vector<VkRect2D>(1, scissors[1]))));
945         params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, scissors[0]))));
946         params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(2, vector<VkRect2D>(1, scissors[2]))));
947         params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(8, 12, WIDTH - 2, HEIGHT - 19, green)));
948 
949         testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_out_of_order_updates", params));
950     }
951 
952     // Dynamic scissor extending outside viewport
953     {
954         TestParams params(groupParams);
955         params.dynamicScissor = true;
956         params.commands.push_back(
957             TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, makeRect2D(30, 40, WIDTH, HEIGHT)))));
958         params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH + 50, HEIGHT + 20, green)));
959 
960         testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_partially_outside_viewport", params));
961     }
962 
963     // Dynamic scissor completely outside viewport
964     {
965         TestParams params(groupParams);
966         params.dynamicScissor = true;
967         params.commands.push_back(TestCommandSp(
968             new DynamicScissorTestCommand(0, vector<VkRect2D>(1, makeRect2D(WIDTH + 30, HEIGHT + 40, WIDTH, HEIGHT)))));
969         params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(100, 100, 20, 30, green)));
970 
971         testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_outside_viewport", params));
972     }
973 
974     // Dynamic scissor outside viewport and touching right border of viewport
975     {
976         TestParams params(groupParams);
977         params.dynamicScissor = true;
978         params.commands.push_back(
979             TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, makeRect2D(WIDTH, 0, WIDTH, HEIGHT)))));
980         params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(100, 100, 20, 30, green)));
981 
982         testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_viewport_border", params));
983     }
984 
985     // Dynamic scissor with offset + extent equal to largest positive int32
986     {
987         TestParams params(groupParams);
988         params.dynamicScissor = true;
989         params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(
990             0, vector<VkRect2D>(1, makeRect2D(100, 100, 0x7fffffff - 100, 0x7fffffff - 100)))));
991         params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH, HEIGHT, green)));
992 
993         testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_max_int32", params));
994     }
995 
996     // 16 dynamic scissors (minimum number required when multiViewport supported)
997     {
998         TestParams params(groupParams);
999         vector<VkRect2D> scissors;
1000         params.dynamicScissor = true;
1001 
1002         for (uint32_t i = 0; i < 16; i++)
1003             scissors.push_back(makeRect2D(10 + i * 3, 20 + i * 2, WIDTH / 2, HEIGHT / 2));
1004 
1005         params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, scissors)));
1006         params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(5, 6, WIDTH - 10, HEIGHT - 2, red)));
1007 
1008         testGroup->addChild(new ScissorTestCase(testCtx, "16_dynamic_scissors", params));
1009     }
1010 
1011     // Two clears with a single dynamic scissor
1012     {
1013         TestParams params(groupParams);
1014         params.dynamicScissor = true;
1015         params.commands.push_back(TestCommandSp(
1016             new DynamicScissorTestCommand(0, vector<VkRect2D>(1, makeRect2D(30, 40, WIDTH - 60, HEIGHT - 80)))));
1017         params.commands.push_back(TestCommandSp(new RectClearTestCommand(10, 10, 50, 50, red)));
1018         params.commands.push_back(TestCommandSp(new RectClearTestCommand(WIDTH - 80, HEIGHT - 100, 30, 40, green)));
1019 
1020         testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_two_clears", params));
1021     }
1022 
1023     // Mixture of quad draws and clears with dynamic scissor updates
1024     {
1025         TestParams params(groupParams);
1026         vector<VkRect2D> scissors;
1027 
1028         params.dynamicScissor = true;
1029 
1030         scissors.push_back(makeRect2D(30, 40, 50, 60));
1031         scissors.push_back(makeRect2D(40, 20, 50, 50));
1032         params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, scissors)));
1033         params.commands.push_back(TestCommandSp(new RectClearTestCommand(10, 10, 50, 50, red)));
1034         params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(40, 30, 50, 50, green)));
1035         scissors[1].extent.width -= 20;
1036         scissors[1].extent.height += 30;
1037         scissors[1].offset.x -= 20;
1038         params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(1, vector<VkRect2D>(1, scissors[1]))));
1039         params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(70, 70, 50, 50, blue)));
1040         params.commands.push_back(TestCommandSp(new RectClearTestCommand(75, 77, 50, 50, yellow)));
1041 
1042         testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_mix", params));
1043     }
1044 
1045     // Static scissor off by one, inside frame buffer border
1046     {
1047         VkExtent2D size = {WIDTH / 2 - 1, HEIGHT / 2 - 1};
1048 
1049         TestParams params(groupParams);
1050 
1051         params.framebufferSize = size;
1052         params.dynamicScissor  = false;
1053         params.staticScissors.push_back(makeRect2D(1, 1, size.width - 2, size.height - 2));
1054         params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH * 4, HEIGHT * 4, red)));
1055 
1056         testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_framebuffer_border_in", params));
1057     }
1058 
1059     // Dynamic scissor off by one, inside frame buffer border
1060     {
1061         VkExtent2D size = {WIDTH / 2 - 1, HEIGHT / 2 - 1};
1062 
1063         TestParams params(groupParams);
1064         vector<VkRect2D> scissors;
1065 
1066         params.framebufferSize = size;
1067         params.dynamicScissor  = true;
1068 
1069         scissors.push_back(makeRect2D(1, 1, size.width - 2, size.height - 2));
1070         params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, scissors)));
1071         params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH * 4, HEIGHT * 4, red)));
1072 
1073         testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_framebuffer_border_in", params));
1074     }
1075 }
1076 
1077 } // namespace
1078 
createScissorTests(TestContext & testCtx,const SharedGroupParams groupParams)1079 TestCaseGroup *createScissorTests(TestContext &testCtx, const SharedGroupParams groupParams)
1080 {
1081     return createTestGroup(testCtx, "scissor", createTests, groupParams);
1082 }
1083 
1084 } // namespace Draw
1085 } // namespace vkt
1086