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 ¶ms);
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 ¶ms)
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