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::__anon8a8f76580111::ColorQuad57 ColorQuad (deUint32 x, deUint32 y, deUint32 width, deUint32 height, Vec4 color)
58 : m_x(x), m_y(y), m_width(width), m_height(height), m_color(color)
59 {
60 }
61
62 deUint32 m_x;
63 deUint32 m_y;
64 deUint32 m_width;
65 deUint32 m_height;
66 Vec4 m_color;
67 };
68
scissorQuad(ColorQuad quad,VkRect2D scissor,VkExtent2D framebufferSize)69 ColorQuad scissorQuad (ColorQuad quad, VkRect2D scissor, VkExtent2D framebufferSize)
70 {
71 int left = quad.m_x;
72 int right = quad.m_x + quad.m_width;
73 int top = quad.m_y;
74 int bottom = quad.m_y + quad.m_height;
75
76 left = de::max(left, scissor.offset.x);
77 left = de::max(left, 0);
78 right = de::min(right, scissor.offset.x + (int)scissor.extent.width);
79 right = de::min(right, (int)framebufferSize.width);
80 top = de::max(top, scissor.offset.y);
81 top = de::max(top, 0);
82 bottom = de::min(bottom, scissor.offset.y + (int)scissor.extent.height);
83 bottom = de::min(bottom, (int)framebufferSize.height);
84
85 return ColorQuad(left, top, de::max(right - left, 0), de::max(bottom - top, 0), quad.m_color);
86 }
87
88 class TestCommand
89 {
90 public:
TestCommand(void)91 TestCommand (void) {};
~TestCommand(void)92 virtual ~TestCommand (void) {};
93
getVertices(deUint32 offset)94 virtual vector<PositionColorVertex> getVertices (deUint32 offset) { DE_UNREF(offset); return vector<PositionColorVertex>(); }
95 virtual void addCommands (const DeviceInterface& vk, VkCommandBuffer cmdBuffer) = 0;
getMaxScissor(void)96 virtual deUint32 getMaxScissor (void) { return 0; }
getQuad(void)97 virtual vector<ColorQuad> getQuad (void) { return vector<ColorQuad>(); }
updateScissors(vector<VkRect2D> scissors)98 virtual vector<VkRect2D> updateScissors (vector<VkRect2D> scissors) { return scissors; }
isScissored(void)99 virtual bool isScissored (void) { return false; }
100
101
102 private:
103 };
104
105 typedef de::SharedPtr<TestCommand> TestCommandSp;
106
107 class QuadDrawTestCommand : public TestCommand
108 {
109 public:
110 QuadDrawTestCommand (deUint32 x, deUint32 y, deUint32 width, deUint32 height, Vec4 color);
~QuadDrawTestCommand(void)111 virtual ~QuadDrawTestCommand (void) {}
112
113 virtual vector<PositionColorVertex> getVertices (deUint32 offset);
114 virtual void addCommands (const DeviceInterface& vk, VkCommandBuffer cmdBuffer);
getQuad(void)115 virtual vector<ColorQuad> getQuad (void) { return vector<ColorQuad>(1, m_quad); }
isScissored(void)116 virtual bool isScissored (void) { return true; }
117 private:
118 deUint32 m_offset;
119 ColorQuad m_quad;
120 };
121
QuadDrawTestCommand(deUint32 x,deUint32 y,deUint32 width,deUint32 height,Vec4 color)122 QuadDrawTestCommand::QuadDrawTestCommand (deUint32 x, deUint32 y, deUint32 width, deUint32 height, Vec4 color)
123 : m_quad(x, y, width, height, color)
124 {
125 }
126
getVertices(deUint32 offset)127 vector<PositionColorVertex> QuadDrawTestCommand::getVertices (deUint32 offset)
128 {
129 vector<PositionColorVertex> vertices;
130 float scaleWidth = 2.0f / (float)WIDTH;
131 float scaleHeight = 2.0f / (float)HEIGHT;
132 Vec4 topLeft (-1.0f + scaleWidth * (float)m_quad.m_x, -1.0f + scaleHeight * (float)m_quad.m_y, 0.0f, 1.0f);
133 Vec4 topRight (-1.0f + scaleWidth * (float)(m_quad.m_x + m_quad.m_width), -1.0f + scaleHeight * (float)m_quad.m_y, 0.0f, 1.0f);
134 Vec4 bottomLeft (-1.0f + scaleWidth * (float)m_quad.m_x, -1.0f + scaleHeight * (float)(m_quad.m_y + m_quad.m_height), 0.0f, 1.0f);
135 Vec4 bottomRight (-1.0f + scaleWidth * (float)(m_quad.m_x + m_quad.m_width), -1.0f + scaleHeight * (float)(m_quad.m_y + m_quad.m_height), 0.0f, 1.0f);
136
137 m_offset = offset;
138
139 vertices.push_back(PositionColorVertex(topLeft, m_quad.m_color));
140 vertices.push_back(PositionColorVertex(bottomRight, m_quad.m_color));
141 vertices.push_back(PositionColorVertex(bottomLeft, m_quad.m_color));
142 vertices.push_back(PositionColorVertex(topLeft, m_quad.m_color));
143 vertices.push_back(PositionColorVertex(topRight, m_quad.m_color));
144 vertices.push_back(PositionColorVertex(bottomRight, m_quad.m_color));
145
146 return vertices;
147 }
148
addCommands(const DeviceInterface & vk,VkCommandBuffer cmdBuffer)149 void QuadDrawTestCommand::addCommands (const DeviceInterface& vk, VkCommandBuffer cmdBuffer)
150 {
151 vk.cmdDraw(cmdBuffer, 6u, 1u, m_offset, 0u);
152 }
153
154 class RectClearTestCommand : public TestCommand
155 {
156 public:
157 RectClearTestCommand (deUint32 x, deUint32 y, deUint32 width, deUint32 height, Vec4 color);
~RectClearTestCommand(void)158 virtual ~RectClearTestCommand (void) {}
159
160 virtual void addCommands (const DeviceInterface& vk, VkCommandBuffer cmdBuffer);
getQuad(void)161 virtual vector<ColorQuad> getQuad (void) { return vector<ColorQuad>(1, m_quad); }
162 private:
163 ColorQuad m_quad;
164 };
165
RectClearTestCommand(deUint32 x,deUint32 y,deUint32 width,deUint32 height,Vec4 color)166 RectClearTestCommand::RectClearTestCommand (deUint32 x, deUint32 y, deUint32 width, deUint32 height, Vec4 color)
167 : m_quad(x, y, width, height, color)
168 {
169 }
170
addCommands(const DeviceInterface & vk,VkCommandBuffer cmdBuffer)171 void RectClearTestCommand::addCommands (const DeviceInterface& vk, VkCommandBuffer cmdBuffer)
172 {
173 const VkClearAttachment attachment =
174 {
175 VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask
176 0u, // deUint32 colorAttachment
177 makeClearValueColor(m_quad.m_color) // VkClearValue clearValue
178 };
179
180 const VkClearRect rect =
181 {
182 makeRect2D(m_quad.m_x, m_quad.m_y, m_quad.m_width, m_quad.m_height), // VkRect2D rect
183 0u, // deUint32 baseArrayLayer
184 1u // deUint32 layerCount
185 };
186
187 vk.cmdClearAttachments(cmdBuffer, 1u, &attachment, 1u, &rect);
188 }
189
190 class DynamicScissorTestCommand : public TestCommand
191 {
192 public:
193 DynamicScissorTestCommand (deUint32 firstScissor, vector<VkRect2D> scissors);
~DynamicScissorTestCommand(void)194 virtual ~DynamicScissorTestCommand (void) {}
195
196 virtual void addCommands (const DeviceInterface& vk, VkCommandBuffer cmdBuffer);
getMaxScissor(void)197 virtual deUint32 getMaxScissor (void) { return m_firstScissor + (deUint32)m_scissors.size(); }
198 virtual vector<VkRect2D> updateScissors (vector<VkRect2D> scissors);
199 private:
200 deUint32 m_firstScissor;
201 vector<VkRect2D> m_scissors;
202 };
203
DynamicScissorTestCommand(deUint32 firstScissor,vector<VkRect2D> scissors)204 DynamicScissorTestCommand::DynamicScissorTestCommand (deUint32 firstScissor, vector<VkRect2D> scissors)
205 : m_firstScissor(firstScissor)
206 , m_scissors(scissors)
207 {
208 }
209
addCommands(const DeviceInterface & vk,VkCommandBuffer cmdBuffer)210 void DynamicScissorTestCommand::addCommands (const DeviceInterface& vk, VkCommandBuffer cmdBuffer)
211 {
212 vk.cmdSetScissor(cmdBuffer, m_firstScissor, (deUint32)m_scissors.size(), m_scissors.data());
213 }
214
updateScissors(vector<VkRect2D> scissors)215 vector<VkRect2D> DynamicScissorTestCommand::updateScissors (vector<VkRect2D> scissors)
216 {
217 for (size_t scissorIdx = 0; scissorIdx < m_scissors.size(); scissorIdx++)
218 {
219 while (scissors.size() <= m_firstScissor + scissorIdx)
220 scissors.push_back(makeRect2D(0, 0)); // Add dummy scissor
221
222 scissors[m_firstScissor + scissorIdx] = m_scissors[scissorIdx];
223 }
224
225 return scissors;
226 }
227
228 struct TestParams
229 {
TestParamsvkt::Draw::__anon8a8f76580111::TestParams230 TestParams() : framebufferSize({WIDTH,HEIGHT}) {};
231
232 bool dynamicScissor;
233 vector<VkRect2D> staticScissors;
234 vector<TestCommandSp> commands;
235 bool usesMultipleScissors;
236 VkExtent2D framebufferSize;
237 };
238
countScissors(TestParams params)239 deUint32 countScissors (TestParams params)
240 {
241 if (params.dynamicScissor)
242 {
243 deUint32 numScissors = 0u;
244
245 for (size_t commandIdx = 0; commandIdx < params.commands.size(); commandIdx++)
246 numScissors = de::max(numScissors, params.commands[commandIdx]->getMaxScissor());
247
248 return numScissors;
249 }
250 else
251 return (deUint32)params.staticScissors.size();
252 }
253
254 class ScissorTestInstance : public TestInstance
255 {
256 public:
257 ScissorTestInstance (Context& context, const TestParams& params);
258 ~ScissorTestInstance (void);
259 TestStatus iterate (void);
260 private:
261 TestParams m_params;
262
263 };
264
ScissorTestInstance(Context & context,const TestParams & params)265 ScissorTestInstance::ScissorTestInstance (Context& context, const TestParams& params)
266 : vkt::TestInstance (context)
267 , m_params (params)
268 {
269 }
270
~ScissorTestInstance(void)271 ScissorTestInstance::~ScissorTestInstance (void)
272 {
273 }
274
275 class ScissorTestCase : public TestCase
276 {
277 public:
278 ScissorTestCase (TestContext& context, const char* name, const char* desc, const TestParams params);
279 ~ScissorTestCase (void);
280 virtual void initPrograms (SourceCollections& programCollection) const;
281 virtual TestInstance* createInstance (Context& context) const;
282 virtual void checkSupport (Context& context) const;
283
284 private:
285 TestParams m_params;
286 };
287
ScissorTestCase(TestContext & context,const char * name,const char * desc,const TestParams params)288 ScissorTestCase::ScissorTestCase (TestContext& context, const char* name, const char* desc, const TestParams params)
289 : vkt::TestCase (context, name, desc)
290 , m_params (params)
291 {
292 m_params.usesMultipleScissors = params.staticScissors.size() > 1;
293
294 for (size_t commandIdx = 0; commandIdx < m_params.commands.size(); commandIdx++)
295 if (m_params.commands[commandIdx]->getMaxScissor() > 1)
296 m_params.usesMultipleScissors = true;
297 }
298
~ScissorTestCase(void)299 ScissorTestCase::~ScissorTestCase (void)
300 {
301 }
302
checkSupport(Context & context) const303 void ScissorTestCase::checkSupport (Context& context) const
304 {
305 if (m_params.usesMultipleScissors)
306 {
307 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
308 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_MULTI_VIEWPORT);
309 }
310 }
311
initPrograms(SourceCollections & programCollection) const312 void ScissorTestCase::initPrograms (SourceCollections& programCollection) const
313 {
314 programCollection.glslSources.add("vert") << glu::VertexSource(
315 "#version 430\n"
316 "layout(location = 0) in vec4 in_position;\n"
317 "layout(location = 1) in vec4 in_color;\n"
318 "layout(location = 0) out vec4 out_color;\n"
319 "void main()\n"
320 "{\n"
321 " gl_Position = in_position;\n"
322 " out_color = in_color;\n"
323 "}\n");
324
325 // Geometry shader draws the same triangles to all viewports
326 string geomSource = string(
327 "#version 430\n"
328 "layout(invocations = ") + de::toString(countScissors(m_params)) + ") in;\n"
329 "layout(triangles) in;\n"
330 "layout(triangle_strip, max_vertices = 3) out;\n"
331 "layout(location = 0) in vec4 in_color[];\n"
332 "layout(location = 0) out vec4 out_color;\n"
333 "void main()\n"
334 "{\n"
335 " for (int i = 0; i < gl_in.length(); i++)\n"
336 " {\n"
337 " gl_ViewportIndex = gl_InvocationID;\n"
338 " gl_Position = gl_in[i].gl_Position;\n"
339 " out_color = in_color[i];\n"
340 " EmitVertex();\n"
341 " }\n"
342 " EndPrimitive();\n"
343 "}\n";
344
345 programCollection.glslSources.add("geom") << glu::GeometrySource(geomSource);
346
347 programCollection.glslSources.add("frag") << glu::FragmentSource(
348 "#version 430\n"
349 "layout(location = 0) in vec4 in_color;\n"
350 "layout(location = 0) out vec4 out_color;\n"
351 "void main()\n"
352 "{\n"
353 " out_color = in_color;\n"
354 "}\n");
355 }
356
createInstance(Context & context) const357 TestInstance* ScissorTestCase::createInstance (Context& context) const
358 {
359 return new ScissorTestInstance(context, m_params);
360 }
361
iterate(void)362 TestStatus ScissorTestInstance::iterate (void)
363 {
364 ConstPixelBufferAccess frame;
365 de::SharedPtr<Image> colorTargetImage;
366 TestLog& log = m_context.getTestContext().getLog();
367 const DeviceInterface& vk = m_context.getDeviceInterface();
368 const VkDevice device = m_context.getDevice();
369 const CmdPoolCreateInfo cmdPoolCreateInfo (m_context.getUniversalQueueFamilyIndex());
370 Move<VkCommandPool> cmdPool = createCommandPool(vk, device, &cmdPoolCreateInfo);
371 Move<VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
372 const Unique<VkShaderModule> vs (createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0));
373 Move<VkShaderModule> gs;
374 const Unique<VkShaderModule> fs (createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0));
375 const deUint32 numScissors = countScissors(m_params);
376 VkDeviceSize vertexBufferSize = 0;
377 de::SharedPtr<Buffer> vertexBuffer;
378 Move<VkRenderPass> renderPass;
379 Move<VkImageView> colorTargetView;
380 Move<VkFramebuffer> framebuffer;
381 Move<VkPipeline> pipeline;
382 TextureLevel refImage;
383 VkExtent2D framebufferSize = m_params.framebufferSize;
384
385 if (m_params.usesMultipleScissors)
386 gs = createShaderModule(vk, device, m_context.getBinaryCollection().get("geom"), 0);
387
388 // Create color buffer image
389 {
390 const VkExtent3D targetImageExtent = { WIDTH, HEIGHT, 1 };
391 const ImageCreateInfo targetImageCreateInfo (VK_IMAGE_TYPE_2D, VK_FORMAT_R8G8B8A8_UNORM, targetImageExtent, 1, 1, VK_SAMPLE_COUNT_1_BIT,
392 VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
393 colorTargetImage = Image::createAndAlloc(vk, device, targetImageCreateInfo, m_context.getDefaultAllocator(), m_context.getUniversalQueueFamilyIndex());
394 }
395
396 // Create render pass and frame buffer
397 {
398 const ImageViewCreateInfo colorTargetViewInfo (colorTargetImage->object(), VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_R8G8B8A8_UNORM);
399 colorTargetView = createImageView(vk, device, &colorTargetViewInfo);
400
401 RenderPassCreateInfo renderPassCreateInfo;
402 renderPassCreateInfo.addAttachment(AttachmentDescription(VK_FORMAT_R8G8B8A8_UNORM,
403 VK_SAMPLE_COUNT_1_BIT,
404 VK_ATTACHMENT_LOAD_OP_CLEAR,
405 VK_ATTACHMENT_STORE_OP_STORE,
406 VK_ATTACHMENT_LOAD_OP_DONT_CARE,
407 VK_ATTACHMENT_STORE_OP_STORE,
408 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
409 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
410
411 const VkAttachmentReference colorAttachmentRef = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
412 vector<VkImageView> colorAttachment (1, *colorTargetView);
413 renderPassCreateInfo.addSubpass(SubpassDescription(VK_PIPELINE_BIND_POINT_GRAPHICS, 0, 0, DE_NULL, 1, &colorAttachmentRef,
414 DE_NULL, AttachmentReference(), 0, DE_NULL));
415
416 renderPass = createRenderPass(vk, device, &renderPassCreateInfo);
417
418 const FramebufferCreateInfo framebufferCreateInfo(*renderPass, colorAttachment, framebufferSize.width, framebufferSize.height, 1);
419
420 framebuffer = createFramebuffer(vk, device, &framebufferCreateInfo);
421 }
422
423 // Create vertex buffer
424 {
425 vector<PositionColorVertex> vertices;
426
427 for (size_t commandIdx = 0; commandIdx < m_params.commands.size(); commandIdx++)
428 {
429 vector<PositionColorVertex> commandVertices = m_params.commands[commandIdx]->getVertices((deUint32)vertices.size());
430 vertices.insert(vertices.end(), commandVertices.begin(), commandVertices.end());
431 }
432
433 vertexBufferSize = vertices.size() * sizeof(PositionColorVertex);
434
435 if (vertexBufferSize > 0)
436 {
437 vertexBuffer = Buffer::createAndAlloc(vk, device, BufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), m_context.getDefaultAllocator(), MemoryRequirement::HostVisible);
438 deUint8* ptr = reinterpret_cast<deUint8*>(vertexBuffer->getBoundMemory().getHostPtr());
439
440 deMemcpy(ptr, vertices.data(), static_cast<size_t>(vertexBufferSize));
441 flushMappedMemoryRange(vk, device, vertexBuffer->getBoundMemory().getMemory(), vertexBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
442 }
443 }
444
445 const PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
446 Move<VkPipelineLayout> pipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
447
448 // Create pipeline
449 {
450 const PipelineCreateInfo::ColorBlendState::Attachment colorBlendState;
451
452 const VkVertexInputBindingDescription vertexInputBindingDescription =
453 {
454 0, // deUintre binding
455 (deUint32)sizeof(Vec4) * 2, // deUint32 stride
456 VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputRate inputRate
457 };
458 const VkViewport viewport = makeViewport(WIDTH, HEIGHT);
459
460 const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] =
461 {
462 { 0u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, 0u },
463 { 1u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, (deUint32)(sizeof(float) * 4) }
464 };
465
466 PipelineCreateInfo::VertexInputState vertexInputState = PipelineCreateInfo::VertexInputState(1, &vertexInputBindingDescription, 2, vertexInputAttributeDescriptions);
467
468 PipelineCreateInfo pipelineCreateInfo(*pipelineLayout, *renderPass, 0, 0);
469 pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vs, "main", VK_SHADER_STAGE_VERTEX_BIT));
470 if (m_params.usesMultipleScissors)
471 pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*gs, "main", VK_SHADER_STAGE_GEOMETRY_BIT));
472 pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fs, "main", VK_SHADER_STAGE_FRAGMENT_BIT));
473 pipelineCreateInfo.addState(PipelineCreateInfo::VertexInputState(vertexInputState));
474 pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST));
475 pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState(1, &colorBlendState));
476 pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState());
477 pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState());
478 pipelineCreateInfo.addState(PipelineCreateInfo::MultiSampleState());
479
480 if (m_params.dynamicScissor)
481 {
482 pipelineCreateInfo.addState(PipelineCreateInfo::DynamicState(vector<VkDynamicState>(1, VK_DYNAMIC_STATE_SCISSOR)));
483 pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(numScissors, vector<VkViewport>(numScissors, viewport), vector<VkRect2D>(numScissors, makeRect2D(0, 0))));
484 }
485 else
486 {
487 pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(numScissors, vector<VkViewport>(numScissors, viewport), m_params.staticScissors));
488 }
489
490 pipeline = createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo);
491 }
492
493 // Queue commands and read results.
494 {
495 const ImageSubresourceRange subresourceRange (VK_IMAGE_ASPECT_COLOR_BIT);
496 const VkRect2D renderArea = makeRect2D(framebufferSize);
497 const VkDeviceSize vertexBufferOffset = 0;
498 const VkOffset3D zeroOffset = { 0, 0, 0 };
499 const Vec4 clearColor (0.0f, 0.0f, 0.0f, 1.0f);
500
501 clearColorImage(vk, device, m_context.getUniversalQueue(), m_context.getUniversalQueueFamilyIndex(), colorTargetImage->object(), clearColor,
502 VK_IMAGE_LAYOUT_UNDEFINED,
503 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
504 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
505
506 beginCommandBuffer(vk, *cmdBuffer, 0u);
507 beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor);
508 if (vertexBufferSize > 0)
509 {
510 const VkBuffer buffer = vertexBuffer->object();
511 vk.cmdBindVertexBuffers(*cmdBuffer, 0, 1, &buffer, &vertexBufferOffset);
512 }
513 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
514
515 for (size_t commandIdx = 0; commandIdx < m_params.commands.size(); commandIdx++)
516 m_params.commands[commandIdx]->addCommands(vk, *cmdBuffer);
517
518 endRenderPass(vk, *cmdBuffer);
519 transition2DImage(vk, *cmdBuffer, colorTargetImage->object(),
520 VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
521 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
522 VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
523 VK_PIPELINE_STAGE_TRANSFER_BIT);
524 endCommandBuffer(vk, *cmdBuffer);
525 submitCommandsAndWait(vk, device, m_context.getUniversalQueue(), cmdBuffer.get());
526
527 frame = colorTargetImage->readSurface(m_context.getUniversalQueue(), m_context.getDefaultAllocator(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, zeroOffset, WIDTH, HEIGHT, VK_IMAGE_ASPECT_COLOR_BIT);
528 }
529
530 // Generate reference
531 {
532 refImage.setStorage(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM), WIDTH, HEIGHT);
533 clear(refImage.getAccess(), Vec4(0.0f, 0.0f, 0.0f, 1.0f));
534
535 vector<VkRect2D> scissors = m_params.staticScissors;
536
537 for (size_t commandIdx = 0; commandIdx < m_params.commands.size(); commandIdx++)
538 {
539 scissors = m_params.commands[commandIdx]->updateScissors(scissors);
540
541 vector<ColorQuad> quad = m_params.commands[commandIdx]->getQuad();
542
543 if (quad.empty())
544 continue;
545
546 for (size_t scissorIdx = 0; scissorIdx < scissors.size(); scissorIdx++)
547 {
548 ColorQuad scissoredQuad = m_params.commands[commandIdx]->isScissored() ? scissorQuad(quad[0], scissors[scissorIdx], framebufferSize) : quad[0];
549
550 if (scissoredQuad.m_width == 0 || scissoredQuad.m_height == 0)
551 continue;
552
553 clear(getSubregion(refImage.getAccess(), scissoredQuad.m_x, scissoredQuad.m_y, 0, scissoredQuad.m_width, scissoredQuad.m_height, 1), scissoredQuad.m_color);
554 }
555 }
556 }
557
558 // Compare results
559 qpTestResult res = QP_TEST_RESULT_PASS;
560
561 if (!intThresholdCompare(log, "Result", "Image comparison result", refImage.getAccess(), frame, UVec4(0), COMPARE_LOG_RESULT))
562 res = QP_TEST_RESULT_FAIL;
563
564 return TestStatus(res, qpGetTestResultName(res));
565 }
566
createTests(TestCaseGroup * testGroup)567 void createTests (TestCaseGroup* testGroup)
568 {
569 TestContext& testCtx = testGroup->getTestContext();
570 const Vec4 red (1.0f, 0.0f, 0.0f, 1.0f);
571 const Vec4 green (0.0f, 1.0f, 0.0f, 1.0f);
572 const Vec4 blue (0.0f, 0.0f, 1.0f, 1.0f);
573 const Vec4 yellow (1.0f, 1.0f, 0.0f, 1.0f);
574
575 // Two quads with a single static scissor
576 {
577 TestParams params;
578 params.dynamicScissor = false;
579 params.staticScissors.push_back(makeRect2D(30, 40, WIDTH - 60, HEIGHT - 80));
580 params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(10, 10, 50, 50, red)));
581 params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(WIDTH - 80, HEIGHT - 100, 30, 40, green)));
582
583 testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_two_quads", "", params));
584 }
585
586 // Two clears with a single static scissor
587 {
588 TestParams params;
589 params.dynamicScissor = false;
590 params.staticScissors.push_back(makeRect2D(30, 40, WIDTH - 60, HEIGHT - 80));
591 params.commands.push_back(TestCommandSp(new RectClearTestCommand(10, 10, 50, 50, red)));
592 params.commands.push_back(TestCommandSp(new RectClearTestCommand(WIDTH - 80, HEIGHT - 100, 30, 40, green)));
593
594 testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_two_clears", "", params));
595 }
596
597 // One quad with two static scissors
598 {
599 TestParams params;
600 params.dynamicScissor = false;
601 params.staticScissors.push_back(makeRect2D(30, 40, WIDTH - 60, HEIGHT - 70));
602 params.staticScissors.push_back(makeRect2D(40, 50, WIDTH - 60, HEIGHT - 70));
603 params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(10, 10, WIDTH - 10, HEIGHT - 10, red)));
604
605 testGroup->addChild(new ScissorTestCase(testCtx, "two_static_scissors_one_quad", "", params));
606 }
607
608 // Static scissor extending outside viewport
609 {
610 TestParams params;
611 params.dynamicScissor = false;
612 params.staticScissors.push_back(makeRect2D(30, 40, WIDTH, HEIGHT));
613 params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH, HEIGHT + 30, green)));
614
615 testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_partially_outside_viewport", "", params));
616 }
617
618 // Static scissor completely outside viewport
619 {
620 TestParams params;
621 params.dynamicScissor = false;
622 params.staticScissors.push_back(makeRect2D(WIDTH + 30, HEIGHT + 40, WIDTH, HEIGHT));
623 params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(100, 100, 20, 30, green)));
624
625 testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_outside_viewport", "", params));
626 }
627
628 // Static scissor outside viewport and touching right border of viewport
629 {
630 TestParams params;
631 params.dynamicScissor = false;
632 params.staticScissors.push_back(makeRect2D(WIDTH, 0, WIDTH, HEIGHT));
633 params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(100, 100, 20, 30, green)));
634
635 testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_viewport_border", "", params));
636 }
637
638 // Static scissor with offset + extent equal to largest positive int32
639 {
640 TestParams params;
641 params.dynamicScissor = false;
642 params.staticScissors.push_back(makeRect2D(100, 100, 0x7fffffff - 100, 0x7fffffff - 100));
643 params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH, HEIGHT, green)));
644
645 testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_max_int32", "", params));
646 }
647
648 // 16 static scissors (minimum number required when multiViewport supported)
649 {
650 TestParams params;
651 params.dynamicScissor = false;
652
653 for (deUint32 i = 0; i < 16; i++)
654 params.staticScissors.push_back(makeRect2D(10 + i * 3, 20 + i * 2, WIDTH / 2, HEIGHT / 2));
655
656 params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(5, 6, WIDTH - 10, HEIGHT - 2, red)));
657
658 testGroup->addChild(new ScissorTestCase(testCtx, "16_static_scissors", "", params));
659 }
660
661 // Two quads with an empty scissor
662 {
663 TestParams params;
664 params.dynamicScissor = false;
665 params.staticScissors.push_back(makeRect2D(0, 0, 0, 0));
666 params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(10, 10, 50, 50, red)));
667 params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(WIDTH - 80, HEIGHT - 100, 30, 40, green)));
668
669 testGroup->addChild(new ScissorTestCase(testCtx, "empty_static_scissor", "", params));
670 }
671
672 // Two quads with a single dynamic scissor
673 {
674 TestParams params;
675 params.dynamicScissor = true;
676 params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, makeRect2D(30, 40, WIDTH - 60, HEIGHT - 80)))));
677 params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(10, 10, 50, 50, red)));
678 params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(WIDTH - 80, HEIGHT - 100, 30, 40, green)));
679
680 testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_two_quads", "", params));
681 }
682
683 // Empty scissor for the first draw
684 {
685 TestParams params;
686 params.dynamicScissor = true;
687 params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, makeRect2D(0, 0, 0, 0)))));
688 params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(10, 10, 50, 50, red)));
689 params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, makeRect2D(30, 40, WIDTH - 60, HEIGHT - 80)))));
690 params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(WIDTH - 80, HEIGHT - 100, 30, 40, green)));
691
692 testGroup->addChild(new ScissorTestCase(testCtx, "empty_dynamic_scissor_first_draw", "", params));
693 }
694
695 // Two quads with three scissors updated in between
696 {
697 TestParams params;
698 VkRect2D rect = makeRect2D(10, 20, WIDTH - 60, HEIGHT - 70);
699 vector<VkRect2D> scissors;
700
701 params.dynamicScissor = true;
702 scissors.push_back(rect);
703 rect.offset.x += 10;
704 rect.offset.y += 10;
705 scissors.push_back(rect);
706 rect.offset.x += 10;
707 rect.offset.y += 10;
708 scissors.push_back(rect);
709
710 params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, scissors)));
711 params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(5, 7, WIDTH - 20, HEIGHT - 9, red)));
712
713 for (size_t scissorIdx = 0; scissorIdx < scissors.size(); scissorIdx++)
714 scissors[scissorIdx].offset.x += 20;
715
716 params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, scissors)));
717 params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(8, 12, WIDTH - 2, HEIGHT - 19, green)));
718
719 testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_updates_between_draws", "", params));
720 }
721
722 // Scissor updates out of order
723 {
724 TestParams params;
725 VkRect2D rect = makeRect2D(10, 20, WIDTH - 60, HEIGHT - 70);
726 vector<VkRect2D> scissors;
727
728 params.dynamicScissor = true;
729 scissors.push_back(rect);
730 rect.offset.x += 10;
731 rect.offset.y += 10;
732 scissors.push_back(rect);
733 rect.offset.x += 10;
734 rect.offset.y += 10;
735 scissors.push_back(rect);
736
737 params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(2, vector<VkRect2D>(1, scissors[2]))));
738 params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(1, vector<VkRect2D>(1, scissors[1]))));
739 params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, scissors[0]))));
740 params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(5, 7, WIDTH - 20, HEIGHT - 9, red)));
741
742 for (size_t scissorIdx = 0; scissorIdx < scissors.size(); scissorIdx++)
743 scissors[scissorIdx].offset.x += 20;
744
745 params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(1, vector<VkRect2D>(1, scissors[1]))));
746 params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, scissors[0]))));
747 params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(2, vector<VkRect2D>(1, scissors[2]))));
748 params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(8, 12, WIDTH - 2, HEIGHT - 19, green)));
749
750 testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_out_of_order_updates", "", params));
751 }
752
753 // Dynamic scissor extending outside viewport
754 {
755 TestParams params;
756 params.dynamicScissor = true;
757 params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, makeRect2D(30, 40, WIDTH, HEIGHT)))));
758 params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH + 50, HEIGHT + 20, green)));
759
760 testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_partially_outside_viewport", "", params));
761 }
762
763 // Dynamic scissor completely outside viewport
764 {
765 TestParams params;
766 params.dynamicScissor = true;
767 params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, makeRect2D(WIDTH + 30, HEIGHT + 40, WIDTH, HEIGHT)))));
768 params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(100, 100, 20, 30, green)));
769
770 testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_outside_viewport", "", params));
771 }
772
773 // Dynamic scissor outside viewport and touching right border of viewport
774 {
775 TestParams params;
776 params.dynamicScissor = true;
777 params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, makeRect2D(WIDTH, 0, WIDTH, HEIGHT)))));
778 params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(100, 100, 20, 30, green)));
779
780 testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_viewport_border", "", params));
781 }
782
783 // Dynamic scissor with offset + extent equal to largest positive int32
784 {
785 TestParams params;
786 params.dynamicScissor = true;
787 params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, makeRect2D(100, 100, 0x7fffffff - 100, 0x7fffffff - 100)))));
788 params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH, HEIGHT, green)));
789
790 testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_max_int32", "", params));
791 }
792
793 // 16 dynamic scissors (minimum number required when multiViewport supported)
794 {
795 TestParams params;
796 vector<VkRect2D> scissors;
797 params.dynamicScissor = true;
798
799 for (deUint32 i = 0; i < 16; i++)
800 scissors.push_back(makeRect2D(10 + i * 3, 20 + i * 2, WIDTH / 2, HEIGHT / 2));
801
802 params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, scissors)));
803 params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(5, 6, WIDTH - 10, HEIGHT - 2, red)));
804
805 testGroup->addChild(new ScissorTestCase(testCtx, "16_dynamic_scissors", "", params));
806 }
807
808 // Two clears with a single dynamic scissor
809 {
810 TestParams params;
811 params.dynamicScissor = true;
812 params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, makeRect2D(30, 40, WIDTH - 60, HEIGHT - 80)))));
813 params.commands.push_back(TestCommandSp(new RectClearTestCommand(10, 10, 50, 50, red)));
814 params.commands.push_back(TestCommandSp(new RectClearTestCommand(WIDTH - 80, HEIGHT - 100, 30, 40, green)));
815
816 testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_two_clears", "", params));
817 }
818
819 // Mixture of quad draws and clears with dynamic scissor updates
820 {
821 TestParams params;
822 vector<VkRect2D> scissors;
823
824 params.dynamicScissor = true;
825 scissors.push_back(makeRect2D(30, 40, 50, 60));
826 scissors.push_back(makeRect2D(40, 20, 50, 50));
827 params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, scissors)));
828 params.commands.push_back(TestCommandSp(new RectClearTestCommand(10, 10, 50, 50, red)));
829 params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(40, 30, 50, 50, green)));
830 scissors[1].extent.width -= 20;
831 scissors[1].extent.height += 30;
832 scissors[1].offset.x -= 20;
833 params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(1, vector<VkRect2D>(1, scissors[1]))));
834 params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(70, 70, 50, 50, blue)));
835 params.commands.push_back(TestCommandSp(new RectClearTestCommand(75, 77, 50, 50, yellow)));
836
837 testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_mix", "", params));
838 }
839
840 // Static scissor off by one, inside frame buffer border
841 {
842 VkExtent2D size =
843 {
844 WIDTH / 2 - 1,
845 HEIGHT / 2 - 1
846 };
847
848 TestParams params;
849
850 params.framebufferSize = size;
851 params.dynamicScissor = false;
852 params.staticScissors.push_back(makeRect2D(1, 1, size.width - 2, size.height - 2));
853 params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH * 4, HEIGHT * 4, red)));
854
855 testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_framebuffer_border_in", "", params));
856 }
857
858 // Dynamic scissor off by one, inside frame buffer border
859 {
860 VkExtent2D size =
861 {
862 WIDTH / 2 - 1,
863 HEIGHT / 2 - 1
864 };
865
866 TestParams params;
867 vector<VkRect2D> scissors;
868
869 params.framebufferSize = size;
870 params.dynamicScissor = true;
871
872 scissors.push_back(makeRect2D(1, 1, size.width - 2, size.height - 2));
873 params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, scissors)));
874 params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH * 4, HEIGHT * 4, red)));
875
876 testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_framebuffer_border_in", "", params));
877 }
878
879 // Static scissor off by one, outside frame buffer border
880 {
881 VkExtent2D size =
882 {
883 WIDTH / 2 - 1,
884 HEIGHT / 2 - 1
885 };
886
887 TestParams params;
888
889 params.framebufferSize = size;
890 params.dynamicScissor = false;
891
892 params.staticScissors.push_back(makeRect2D(0, 0, size.width + 1, size.height + 1));
893 params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH * 4, HEIGHT * 4, red)));
894
895 testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_framebuffer_border_out", "", params));
896 }
897
898 // Dynamic scissor off by one, outside frame buffer border
899 {
900 VkExtent2D size =
901 {
902 WIDTH / 2 - 1,
903 HEIGHT / 2 - 1
904 };
905
906 TestParams params;
907 vector<VkRect2D> scissors;
908
909 params.framebufferSize = size;
910 params.dynamicScissor = true;
911
912 scissors.push_back(makeRect2D(0, 0, size.width + 1, size.height + 1));
913 params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, scissors)));
914 params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH * 4, HEIGHT * 4, red)));
915
916 testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_framebuffer_border_out", "", params));
917 }
918
919 // Static oversized scissor, exceeds frame buffer and image attachment sizes
920 {
921 VkExtent2D size =
922 {
923 WIDTH / 2 - 1,
924 HEIGHT / 2 - 1
925 };
926
927 TestParams params;
928
929 params.framebufferSize = size;
930 params.dynamicScissor = false;
931
932 params.staticScissors.push_back(makeRect2D(0, 0, WIDTH * 2, HEIGHT * 2));
933 params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH * 4, HEIGHT * 4, red)));
934
935 testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_oversized", "", params));
936 }
937
938 // Dynamic oversized scissor, exceeds frame buffer and image attachment sizes
939 {
940 VkExtent2D size =
941 {
942 WIDTH / 2 - 1,
943 HEIGHT / 2 - 1
944 };
945
946 TestParams params;
947 vector<VkRect2D> scissors;
948
949 params.framebufferSize = size;
950 params.dynamicScissor = true;
951
952 scissors.push_back(makeRect2D(0, 0, WIDTH * 2, HEIGHT * 2));
953 params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, scissors)));
954 params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH * 4, HEIGHT * 4, red)));
955
956 testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_oversized", "", params));
957 }
958 }
959
960 } // anonymous
961
createScissorTests(TestContext & testCtx)962 TestCaseGroup* createScissorTests (TestContext& testCtx)
963 {
964 return createTestGroup(testCtx, "scissor", "Scissor tests", createTests);
965 }
966
967 } // Draw
968 } // vkt
969