/*------------------------------------------------------------------------ * Vulkan Conformance Tests * ------------------------ * * Copyright (c) 2019 Google Inc. * Copyright (c) 2019 The Khronos Group Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief Scissoring tests *//*--------------------------------------------------------------------*/ #include "vktDrawScissorTests.hpp" #include "vktDrawBaseClass.hpp" #include "vkQueryUtil.hpp" #include "vkCmdUtil.hpp" #include "vkTypeUtil.hpp" #include "vktTestGroupUtil.hpp" #include "tcuTestCase.hpp" #include "tcuTextureUtil.hpp" #include "tcuImageCompare.hpp" #include namespace vkt { namespace Draw { namespace { using namespace vk; using namespace std; using namespace tcu; enum { WIDTH = 256, HEIGHT = 256 }; struct ColorQuad { ColorQuad (deUint32 x, deUint32 y, deUint32 width, deUint32 height, Vec4 color) : m_x(x), m_y(y), m_width(width), m_height(height), m_color(color) { } deUint32 m_x; deUint32 m_y; deUint32 m_width; deUint32 m_height; Vec4 m_color; }; ColorQuad scissorQuad (ColorQuad quad, VkRect2D scissor, VkExtent2D framebufferSize) { int left = quad.m_x; int right = quad.m_x + quad.m_width; int top = quad.m_y; int bottom = quad.m_y + quad.m_height; left = de::max(left, scissor.offset.x); left = de::max(left, 0); right = de::min(right, scissor.offset.x + (int)scissor.extent.width); right = de::min(right, (int)framebufferSize.width); top = de::max(top, scissor.offset.y); top = de::max(top, 0); bottom = de::min(bottom, scissor.offset.y + (int)scissor.extent.height); bottom = de::min(bottom, (int)framebufferSize.height); return ColorQuad(left, top, de::max(right - left, 0), de::max(bottom - top, 0), quad.m_color); } class TestCommand { public: TestCommand (void) {} virtual ~TestCommand (void) {} virtual vector getVertices (deUint32 offset) { DE_UNREF(offset); return vector(); } virtual void addCommands (const DeviceInterface& vk, VkCommandBuffer cmdBuffer) = 0; virtual deUint32 getMaxScissor (void) { return 0; } virtual vector getQuad (void) { return vector(); } virtual vector updateScissors (vector scissors) { return scissors; } virtual bool isScissored (void) { return false; } private: }; typedef de::SharedPtr TestCommandSp; class QuadDrawTestCommand : public TestCommand { public: QuadDrawTestCommand (deUint32 x, deUint32 y, deUint32 width, deUint32 height, Vec4 color); virtual ~QuadDrawTestCommand (void) {} virtual vector getVertices (deUint32 offset); virtual void addCommands (const DeviceInterface& vk, VkCommandBuffer cmdBuffer); virtual vector getQuad (void) { return vector(1, m_quad); } virtual bool isScissored (void) { return true; } private: deUint32 m_offset; ColorQuad m_quad; }; QuadDrawTestCommand::QuadDrawTestCommand (deUint32 x, deUint32 y, deUint32 width, deUint32 height, Vec4 color) : m_offset(0) , m_quad(x, y, width, height, color) { } vector QuadDrawTestCommand::getVertices (deUint32 offset) { vector vertices; float scaleWidth = 2.0f / (float)WIDTH; float scaleHeight = 2.0f / (float)HEIGHT; Vec4 topLeft (-1.0f + scaleWidth * (float)m_quad.m_x, -1.0f + scaleHeight * (float)m_quad.m_y, 0.0f, 1.0f); 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); 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); 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); m_offset = offset; vertices.push_back(PositionColorVertex(topLeft, m_quad.m_color)); vertices.push_back(PositionColorVertex(bottomRight, m_quad.m_color)); vertices.push_back(PositionColorVertex(bottomLeft, m_quad.m_color)); vertices.push_back(PositionColorVertex(topLeft, m_quad.m_color)); vertices.push_back(PositionColorVertex(topRight, m_quad.m_color)); vertices.push_back(PositionColorVertex(bottomRight, m_quad.m_color)); return vertices; } void QuadDrawTestCommand::addCommands (const DeviceInterface& vk, VkCommandBuffer cmdBuffer) { vk.cmdDraw(cmdBuffer, 6u, 1u, m_offset, 0u); } class RectClearTestCommand : public TestCommand { public: RectClearTestCommand (deUint32 x, deUint32 y, deUint32 width, deUint32 height, Vec4 color); virtual ~RectClearTestCommand (void) {} virtual void addCommands (const DeviceInterface& vk, VkCommandBuffer cmdBuffer); virtual vector getQuad (void) { return vector(1, m_quad); } private: ColorQuad m_quad; }; RectClearTestCommand::RectClearTestCommand (deUint32 x, deUint32 y, deUint32 width, deUint32 height, Vec4 color) : m_quad(x, y, width, height, color) { } void RectClearTestCommand::addCommands (const DeviceInterface& vk, VkCommandBuffer cmdBuffer) { const VkClearAttachment attachment = { VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask 0u, // deUint32 colorAttachment makeClearValueColor(m_quad.m_color) // VkClearValue clearValue }; const VkClearRect rect = { makeRect2D(m_quad.m_x, m_quad.m_y, m_quad.m_width, m_quad.m_height), // VkRect2D rect 0u, // deUint32 baseArrayLayer 1u // deUint32 layerCount }; vk.cmdClearAttachments(cmdBuffer, 1u, &attachment, 1u, &rect); } class DynamicScissorTestCommand : public TestCommand { public: DynamicScissorTestCommand (deUint32 firstScissor, vector scissors); virtual ~DynamicScissorTestCommand (void) {} virtual void addCommands (const DeviceInterface& vk, VkCommandBuffer cmdBuffer); virtual deUint32 getMaxScissor (void) { return m_firstScissor + (deUint32)m_scissors.size(); } virtual vector updateScissors (vector scissors); private: deUint32 m_firstScissor; vector m_scissors; }; DynamicScissorTestCommand::DynamicScissorTestCommand (deUint32 firstScissor, vector scissors) : m_firstScissor(firstScissor) , m_scissors(scissors) { } void DynamicScissorTestCommand::addCommands (const DeviceInterface& vk, VkCommandBuffer cmdBuffer) { vk.cmdSetScissor(cmdBuffer, m_firstScissor, (deUint32)m_scissors.size(), m_scissors.data()); } vector DynamicScissorTestCommand::updateScissors (vector scissors) { for (size_t scissorIdx = 0; scissorIdx < m_scissors.size(); scissorIdx++) { while (scissors.size() <= m_firstScissor + scissorIdx) scissors.push_back(makeRect2D(0, 0)); // Add dummy scissor scissors[m_firstScissor + scissorIdx] = m_scissors[scissorIdx]; } return scissors; } struct TestParams { TestParams() : framebufferSize({WIDTH,HEIGHT}) {} bool dynamicScissor; vector staticScissors; vector commands; bool usesMultipleScissors; bool usesDynamicRendering; VkExtent2D framebufferSize; }; deUint32 countScissors (TestParams params) { if (params.dynamicScissor) { deUint32 numScissors = 0u; for (size_t commandIdx = 0; commandIdx < params.commands.size(); commandIdx++) numScissors = de::max(numScissors, params.commands[commandIdx]->getMaxScissor()); return numScissors; } else return (deUint32)params.staticScissors.size(); } class ScissorTestInstance : public TestInstance { public: ScissorTestInstance (Context& context, const TestParams& params); ~ScissorTestInstance (void); TestStatus iterate (void); private: TestParams m_params; }; ScissorTestInstance::ScissorTestInstance (Context& context, const TestParams& params) : vkt::TestInstance (context) , m_params (params) { } ScissorTestInstance::~ScissorTestInstance (void) { } class ScissorTestCase : public TestCase { public: ScissorTestCase (TestContext& context, const char* name, const char* desc, const TestParams params); ~ScissorTestCase (void); virtual void initPrograms (SourceCollections& programCollection) const; virtual TestInstance* createInstance (Context& context) const; virtual void checkSupport (Context& context) const; private: TestParams m_params; }; ScissorTestCase::ScissorTestCase (TestContext& context, const char* name, const char* desc, const TestParams params) : vkt::TestCase (context, name, desc) , m_params (params) { m_params.usesMultipleScissors = params.staticScissors.size() > 1; for (size_t commandIdx = 0; commandIdx < m_params.commands.size(); commandIdx++) if (m_params.commands[commandIdx]->getMaxScissor() > 1) m_params.usesMultipleScissors = true; } ScissorTestCase::~ScissorTestCase (void) { } void ScissorTestCase::checkSupport (Context& context) const { if (m_params.usesDynamicRendering) context.requireDeviceFunctionality("VK_KHR_dynamic_rendering"); if (m_params.usesMultipleScissors) { context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER); context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_MULTI_VIEWPORT); } } void ScissorTestCase::initPrograms (SourceCollections& programCollection) const { programCollection.glslSources.add("vert") << glu::VertexSource( "#version 430\n" "layout(location = 0) in vec4 in_position;\n" "layout(location = 1) in vec4 in_color;\n" "layout(location = 0) out vec4 out_color;\n" "void main()\n" "{\n" " gl_Position = in_position;\n" " out_color = in_color;\n" "}\n"); // Geometry shader draws the same triangles to all viewports string geomSource = string( "#version 430\n" "layout(invocations = ") + de::toString(countScissors(m_params)) + ") in;\n" "layout(triangles) in;\n" "layout(triangle_strip, max_vertices = 3) out;\n" "layout(location = 0) in vec4 in_color[];\n" "layout(location = 0) out vec4 out_color;\n" "void main()\n" "{\n" " for (int i = 0; i < gl_in.length(); i++)\n" " {\n" " gl_ViewportIndex = gl_InvocationID;\n" " gl_Position = gl_in[i].gl_Position;\n" " out_color = in_color[i];\n" " EmitVertex();\n" " }\n" " EndPrimitive();\n" "}\n"; programCollection.glslSources.add("geom") << glu::GeometrySource(geomSource); programCollection.glslSources.add("frag") << glu::FragmentSource( "#version 430\n" "layout(location = 0) in vec4 in_color;\n" "layout(location = 0) out vec4 out_color;\n" "void main()\n" "{\n" " out_color = in_color;\n" "}\n"); } TestInstance* ScissorTestCase::createInstance (Context& context) const { return new ScissorTestInstance(context, m_params); } TestStatus ScissorTestInstance::iterate (void) { ConstPixelBufferAccess frame; VkFormat colorImageFormat = VK_FORMAT_R8G8B8A8_UNORM; de::SharedPtr colorTargetImage; TestLog& log = m_context.getTestContext().getLog(); const DeviceInterface& vk = m_context.getDeviceInterface(); const VkDevice device = m_context.getDevice(); const CmdPoolCreateInfo cmdPoolCreateInfo (m_context.getUniversalQueueFamilyIndex()); Move cmdPool = createCommandPool(vk, device, &cmdPoolCreateInfo); Move cmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY); const Unique vs (createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0)); Move gs; const Unique fs (createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0)); const deUint32 numScissors = countScissors(m_params); VkDeviceSize vertexBufferSize = 0; de::SharedPtr vertexBuffer; Move renderPass; Move colorTargetView; Move framebuffer; Move pipeline; TextureLevel refImage; VkExtent2D framebufferSize = m_params.framebufferSize; if (m_params.usesMultipleScissors) gs = createShaderModule(vk, device, m_context.getBinaryCollection().get("geom"), 0); // Create color buffer image { const VkExtent3D targetImageExtent = { WIDTH, HEIGHT, 1 }; const ImageCreateInfo targetImageCreateInfo (VK_IMAGE_TYPE_2D, colorImageFormat, targetImageExtent, 1, 1, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); colorTargetImage = Image::createAndAlloc(vk, device, targetImageCreateInfo, m_context.getDefaultAllocator(), m_context.getUniversalQueueFamilyIndex()); } const ImageViewCreateInfo colorTargetViewInfo(colorTargetImage->object(), VK_IMAGE_VIEW_TYPE_2D, colorImageFormat); colorTargetView = createImageView(vk, device, &colorTargetViewInfo); // Create render pass if (!m_params.usesDynamicRendering) { RenderPassCreateInfo renderPassCreateInfo; renderPassCreateInfo.addAttachment(AttachmentDescription(colorImageFormat, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_STORE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)); const VkAttachmentReference colorAttachmentRef = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; renderPassCreateInfo.addSubpass(SubpassDescription(VK_PIPELINE_BIND_POINT_GRAPHICS, 0, 0, DE_NULL, 1, &colorAttachmentRef, DE_NULL, AttachmentReference(), 0, DE_NULL)); renderPass = createRenderPass(vk, device, &renderPassCreateInfo); // Create framebuffer vector colorAttachment { *colorTargetView }; const FramebufferCreateInfo framebufferCreateInfo(*renderPass, colorAttachment, framebufferSize.width, framebufferSize.height, 1); framebuffer = createFramebuffer(vk, device, &framebufferCreateInfo); } // Create vertex buffer { vector vertices; for (size_t commandIdx = 0; commandIdx < m_params.commands.size(); commandIdx++) { vector commandVertices = m_params.commands[commandIdx]->getVertices((deUint32)vertices.size()); vertices.insert(vertices.end(), commandVertices.begin(), commandVertices.end()); } vertexBufferSize = vertices.size() * sizeof(PositionColorVertex); if (vertexBufferSize > 0) { vertexBuffer = Buffer::createAndAlloc(vk, device, BufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), m_context.getDefaultAllocator(), MemoryRequirement::HostVisible); deUint8* ptr = reinterpret_cast(vertexBuffer->getBoundMemory().getHostPtr()); deMemcpy(ptr, vertices.data(), static_cast(vertexBufferSize)); flushMappedMemoryRange(vk, device, vertexBuffer->getBoundMemory().getMemory(), vertexBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE); } } const PipelineLayoutCreateInfo pipelineLayoutCreateInfo; Move pipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo); // Create pipeline { const PipelineCreateInfo::ColorBlendState::Attachment colorBlendState; const VkVertexInputBindingDescription vertexInputBindingDescription = { 0, // deUintre binding (deUint32)sizeof(Vec4) * 2, // deUint32 stride VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputRate inputRate }; const VkViewport viewport = makeViewport(WIDTH, HEIGHT); const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] = { { 0u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, 0u }, { 1u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, (deUint32)(sizeof(float) * 4) } }; PipelineCreateInfo::VertexInputState vertexInputState = PipelineCreateInfo::VertexInputState(1, &vertexInputBindingDescription, 2, vertexInputAttributeDescriptions); PipelineCreateInfo pipelineCreateInfo(*pipelineLayout, *renderPass, 0, 0); pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vs, "main", VK_SHADER_STAGE_VERTEX_BIT)); if (m_params.usesMultipleScissors) pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*gs, "main", VK_SHADER_STAGE_GEOMETRY_BIT)); pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fs, "main", VK_SHADER_STAGE_FRAGMENT_BIT)); pipelineCreateInfo.addState(PipelineCreateInfo::VertexInputState(vertexInputState)); pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)); pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState(1, &colorBlendState)); pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState()); pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState()); pipelineCreateInfo.addState(PipelineCreateInfo::MultiSampleState()); if (m_params.dynamicScissor) { pipelineCreateInfo.addState(PipelineCreateInfo::DynamicState(vector(1, VK_DYNAMIC_STATE_SCISSOR))); pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(numScissors, vector(numScissors, viewport), vector(numScissors, makeRect2D(0, 0)))); } else { pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(numScissors, vector(numScissors, viewport), m_params.staticScissors)); } VkPipelineRenderingCreateInfoKHR renderingCreateInfo { VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR, DE_NULL, 0u, 1u, &colorImageFormat, VK_FORMAT_UNDEFINED, VK_FORMAT_UNDEFINED }; if (m_params.usesDynamicRendering) pipelineCreateInfo.pNext = &renderingCreateInfo; pipeline = createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo); } // Queue commands and read results. { const ImageSubresourceRange subresourceRange (VK_IMAGE_ASPECT_COLOR_BIT); const VkRect2D renderArea = makeRect2D(framebufferSize); const VkDeviceSize vertexBufferOffset = 0; const VkOffset3D zeroOffset = { 0, 0, 0 }; const tcu::Vec4 clearColor = { 0.0f, 0.0f, 0.0f, 1.0f }; const VkClearValue clearValue = makeClearValueColor(clearColor); clearColorImage(vk, device, m_context.getUniversalQueue(), m_context.getUniversalQueueFamilyIndex(), colorTargetImage->object(), clearColor, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); beginCommandBuffer(vk, *cmdBuffer, 0u); if (m_params.usesDynamicRendering) beginRendering(vk, *cmdBuffer, *colorTargetView, renderArea, clearValue, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ATTACHMENT_LOAD_OP_CLEAR); else beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor); if (vertexBufferSize > 0) { const VkBuffer buffer = vertexBuffer->object(); vk.cmdBindVertexBuffers(*cmdBuffer, 0, 1, &buffer, &vertexBufferOffset); } vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline); for (size_t commandIdx = 0; commandIdx < m_params.commands.size(); commandIdx++) m_params.commands[commandIdx]->addCommands(vk, *cmdBuffer); if (m_params.usesDynamicRendering) endRendering(vk, *cmdBuffer); else endRenderPass(vk, *cmdBuffer); transition2DImage(vk, *cmdBuffer, colorTargetImage->object(), VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); endCommandBuffer(vk, *cmdBuffer); submitCommandsAndWait(vk, device, m_context.getUniversalQueue(), cmdBuffer.get()); frame = colorTargetImage->readSurface(m_context.getUniversalQueue(), m_context.getDefaultAllocator(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, zeroOffset, WIDTH, HEIGHT, VK_IMAGE_ASPECT_COLOR_BIT); } // Generate reference { refImage.setStorage(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM), WIDTH, HEIGHT); clear(refImage.getAccess(), Vec4(0.0f, 0.0f, 0.0f, 1.0f)); vector scissors = m_params.staticScissors; for (size_t commandIdx = 0; commandIdx < m_params.commands.size(); commandIdx++) { scissors = m_params.commands[commandIdx]->updateScissors(scissors); vector quad = m_params.commands[commandIdx]->getQuad(); if (quad.empty()) continue; for (size_t scissorIdx = 0; scissorIdx < scissors.size(); scissorIdx++) { ColorQuad scissoredQuad = m_params.commands[commandIdx]->isScissored() ? scissorQuad(quad[0], scissors[scissorIdx], framebufferSize) : quad[0]; if (scissoredQuad.m_width == 0 || scissoredQuad.m_height == 0) continue; clear(getSubregion(refImage.getAccess(), scissoredQuad.m_x, scissoredQuad.m_y, 0, scissoredQuad.m_width, scissoredQuad.m_height, 1), scissoredQuad.m_color); } } } // Compare results qpTestResult res = QP_TEST_RESULT_PASS; if (!intThresholdCompare(log, "Result", "Image comparison result", refImage.getAccess(), frame, UVec4(0), COMPARE_LOG_RESULT)) res = QP_TEST_RESULT_FAIL; return TestStatus(res, qpGetTestResultName(res)); } void createTests (TestCaseGroup* testGroup, bool useDynamicRendering) { TestContext& testCtx = testGroup->getTestContext(); const Vec4 red (1.0f, 0.0f, 0.0f, 1.0f); const Vec4 green (0.0f, 1.0f, 0.0f, 1.0f); const Vec4 blue (0.0f, 0.0f, 1.0f, 1.0f); const Vec4 yellow (1.0f, 1.0f, 0.0f, 1.0f); // Two quads with a single static scissor { TestParams params; params.dynamicScissor = false; params.usesDynamicRendering = useDynamicRendering; params.staticScissors.push_back(makeRect2D(30, 40, WIDTH - 60, HEIGHT - 80)); params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(10, 10, 50, 50, red))); params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(WIDTH - 80, HEIGHT - 100, 30, 40, green))); testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_two_quads", "", params)); } // Two clears with a single static scissor { TestParams params; params.dynamicScissor = false; params.usesDynamicRendering = useDynamicRendering; params.staticScissors.push_back(makeRect2D(30, 40, WIDTH - 60, HEIGHT - 80)); params.commands.push_back(TestCommandSp(new RectClearTestCommand(10, 10, 50, 50, red))); params.commands.push_back(TestCommandSp(new RectClearTestCommand(WIDTH - 80, HEIGHT - 100, 30, 40, green))); testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_two_clears", "", params)); } // One quad with two static scissors { TestParams params; params.dynamicScissor = false; params.usesDynamicRendering = useDynamicRendering; params.staticScissors.push_back(makeRect2D(30, 40, WIDTH - 60, HEIGHT - 70)); params.staticScissors.push_back(makeRect2D(40, 50, WIDTH - 60, HEIGHT - 70)); params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(10, 10, WIDTH - 10, HEIGHT - 10, red))); testGroup->addChild(new ScissorTestCase(testCtx, "two_static_scissors_one_quad", "", params)); } // Static scissor extending outside viewport { TestParams params; params.dynamicScissor = false; params.usesDynamicRendering = useDynamicRendering; params.staticScissors.push_back(makeRect2D(30, 40, WIDTH, HEIGHT)); params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH, HEIGHT + 30, green))); testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_partially_outside_viewport", "", params)); } // Static scissor completely outside viewport { TestParams params; params.dynamicScissor = false; params.usesDynamicRendering = useDynamicRendering; params.staticScissors.push_back(makeRect2D(WIDTH + 30, HEIGHT + 40, WIDTH, HEIGHT)); params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(100, 100, 20, 30, green))); testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_outside_viewport", "", params)); } // Static scissor outside viewport and touching right border of viewport { TestParams params; params.dynamicScissor = false; params.usesDynamicRendering = useDynamicRendering; params.staticScissors.push_back(makeRect2D(WIDTH, 0, WIDTH, HEIGHT)); params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(100, 100, 20, 30, green))); testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_viewport_border", "", params)); } // Static scissor with offset + extent equal to largest positive int32 { TestParams params; params.dynamicScissor = false; params.usesDynamicRendering = useDynamicRendering; params.staticScissors.push_back(makeRect2D(100, 100, 0x7fffffff - 100, 0x7fffffff - 100)); params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH, HEIGHT, green))); testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_max_int32", "", params)); } // 16 static scissors (minimum number required when multiViewport supported) { TestParams params; params.dynamicScissor = false; params.usesDynamicRendering = useDynamicRendering; for (deUint32 i = 0; i < 16; i++) params.staticScissors.push_back(makeRect2D(10 + i * 3, 20 + i * 2, WIDTH / 2, HEIGHT / 2)); params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(5, 6, WIDTH - 10, HEIGHT - 2, red))); testGroup->addChild(new ScissorTestCase(testCtx, "16_static_scissors", "", params)); } // Two quads with an empty scissor { TestParams params; params.dynamicScissor = false; params.usesDynamicRendering = useDynamicRendering; params.staticScissors.push_back(makeRect2D(0, 0, 0, 0)); params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(10, 10, 50, 50, red))); params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(WIDTH - 80, HEIGHT - 100, 30, 40, green))); testGroup->addChild(new ScissorTestCase(testCtx, "empty_static_scissor", "", params)); } // Two quads with a single dynamic scissor { TestParams params; params.dynamicScissor = true; params.usesDynamicRendering = useDynamicRendering; params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector(1, makeRect2D(30, 40, WIDTH - 60, HEIGHT - 80))))); params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(10, 10, 50, 50, red))); params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(WIDTH - 80, HEIGHT - 100, 30, 40, green))); testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_two_quads", "", params)); } // Empty scissor for the first draw { TestParams params; params.dynamicScissor = true; params.usesDynamicRendering = useDynamicRendering; params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector(1, makeRect2D(0, 0, 0, 0))))); params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(10, 10, 50, 50, red))); params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector(1, makeRect2D(30, 40, WIDTH - 60, HEIGHT - 80))))); params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(WIDTH - 80, HEIGHT - 100, 30, 40, green))); testGroup->addChild(new ScissorTestCase(testCtx, "empty_dynamic_scissor_first_draw", "", params)); } // Two quads with three scissors updated in between { TestParams params; VkRect2D rect = makeRect2D(10, 20, WIDTH - 60, HEIGHT - 70); vector scissors; params.dynamicScissor = true; params.usesDynamicRendering = useDynamicRendering; scissors.push_back(rect); rect.offset.x += 10; rect.offset.y += 10; scissors.push_back(rect); rect.offset.x += 10; rect.offset.y += 10; scissors.push_back(rect); params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, scissors))); params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(5, 7, WIDTH - 20, HEIGHT - 9, red))); for (size_t scissorIdx = 0; scissorIdx < scissors.size(); scissorIdx++) scissors[scissorIdx].offset.x += 20; params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, scissors))); params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(8, 12, WIDTH - 2, HEIGHT - 19, green))); testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_updates_between_draws", "", params)); } // Scissor updates out of order { TestParams params; VkRect2D rect = makeRect2D(10, 20, WIDTH - 60, HEIGHT - 70); vector scissors; params.dynamicScissor = true; params.usesDynamicRendering = useDynamicRendering; scissors.push_back(rect); rect.offset.x += 10; rect.offset.y += 10; scissors.push_back(rect); rect.offset.x += 10; rect.offset.y += 10; scissors.push_back(rect); params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(2, vector(1, scissors[2])))); params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(1, vector(1, scissors[1])))); params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector(1, scissors[0])))); params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(5, 7, WIDTH - 20, HEIGHT - 9, red))); for (size_t scissorIdx = 0; scissorIdx < scissors.size(); scissorIdx++) scissors[scissorIdx].offset.x += 20; params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(1, vector(1, scissors[1])))); params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector(1, scissors[0])))); params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(2, vector(1, scissors[2])))); params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(8, 12, WIDTH - 2, HEIGHT - 19, green))); testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_out_of_order_updates", "", params)); } // Dynamic scissor extending outside viewport { TestParams params; params.dynamicScissor = true; params.usesDynamicRendering = useDynamicRendering; params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector(1, makeRect2D(30, 40, WIDTH, HEIGHT))))); params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH + 50, HEIGHT + 20, green))); testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_partially_outside_viewport", "", params)); } // Dynamic scissor completely outside viewport { TestParams params; params.dynamicScissor = true; params.usesDynamicRendering = useDynamicRendering; params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector(1, makeRect2D(WIDTH + 30, HEIGHT + 40, WIDTH, HEIGHT))))); params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(100, 100, 20, 30, green))); testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_outside_viewport", "", params)); } // Dynamic scissor outside viewport and touching right border of viewport { TestParams params; params.dynamicScissor = true; params.usesDynamicRendering = useDynamicRendering; params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector(1, makeRect2D(WIDTH, 0, WIDTH, HEIGHT))))); params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(100, 100, 20, 30, green))); testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_viewport_border", "", params)); } // Dynamic scissor with offset + extent equal to largest positive int32 { TestParams params; params.dynamicScissor = true; params.usesDynamicRendering = useDynamicRendering; params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector(1, makeRect2D(100, 100, 0x7fffffff - 100, 0x7fffffff - 100))))); params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH, HEIGHT, green))); testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_max_int32", "", params)); } // 16 dynamic scissors (minimum number required when multiViewport supported) { TestParams params; vector scissors; params.dynamicScissor = true; params.usesDynamicRendering = useDynamicRendering; for (deUint32 i = 0; i < 16; i++) scissors.push_back(makeRect2D(10 + i * 3, 20 + i * 2, WIDTH / 2, HEIGHT / 2)); params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, scissors))); params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(5, 6, WIDTH - 10, HEIGHT - 2, red))); testGroup->addChild(new ScissorTestCase(testCtx, "16_dynamic_scissors", "", params)); } // Two clears with a single dynamic scissor { TestParams params; params.dynamicScissor = true; params.usesDynamicRendering = useDynamicRendering; params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector(1, makeRect2D(30, 40, WIDTH - 60, HEIGHT - 80))))); params.commands.push_back(TestCommandSp(new RectClearTestCommand(10, 10, 50, 50, red))); params.commands.push_back(TestCommandSp(new RectClearTestCommand(WIDTH - 80, HEIGHT - 100, 30, 40, green))); testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_two_clears", "", params)); } // Mixture of quad draws and clears with dynamic scissor updates { TestParams params; vector scissors; params.dynamicScissor = true; params.usesDynamicRendering = useDynamicRendering; scissors.push_back(makeRect2D(30, 40, 50, 60)); scissors.push_back(makeRect2D(40, 20, 50, 50)); params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, scissors))); params.commands.push_back(TestCommandSp(new RectClearTestCommand(10, 10, 50, 50, red))); params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(40, 30, 50, 50, green))); scissors[1].extent.width -= 20; scissors[1].extent.height += 30; scissors[1].offset.x -= 20; params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(1, vector(1, scissors[1])))); params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(70, 70, 50, 50, blue))); params.commands.push_back(TestCommandSp(new RectClearTestCommand(75, 77, 50, 50, yellow))); testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_mix", "", params)); } // Static scissor off by one, inside frame buffer border { VkExtent2D size = { WIDTH / 2 - 1, HEIGHT / 2 - 1 }; TestParams params; params.framebufferSize = size; params.dynamicScissor = false; params.usesDynamicRendering = useDynamicRendering; params.staticScissors.push_back(makeRect2D(1, 1, size.width - 2, size.height - 2)); params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH * 4, HEIGHT * 4, red))); testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_framebuffer_border_in", "", params)); } // Dynamic scissor off by one, inside frame buffer border { VkExtent2D size = { WIDTH / 2 - 1, HEIGHT / 2 - 1 }; TestParams params; vector scissors; params.framebufferSize = size; params.dynamicScissor = true; params.usesDynamicRendering = useDynamicRendering; scissors.push_back(makeRect2D(1, 1, size.width - 2, size.height - 2)); params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, scissors))); params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH * 4, HEIGHT * 4, red))); testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_framebuffer_border_in", "", params)); } // Static scissor off by one, outside frame buffer border { VkExtent2D size = { WIDTH / 2 - 1, HEIGHT / 2 - 1 }; TestParams params; params.framebufferSize = size; params.dynamicScissor = false; params.usesDynamicRendering = useDynamicRendering; params.staticScissors.push_back(makeRect2D(0, 0, size.width + 1, size.height + 1)); params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH * 4, HEIGHT * 4, red))); testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_framebuffer_border_out", "", params)); } // Dynamic scissor off by one, outside frame buffer border { VkExtent2D size = { WIDTH / 2 - 1, HEIGHT / 2 - 1 }; TestParams params; vector scissors; params.framebufferSize = size; params.dynamicScissor = true; params.usesDynamicRendering = useDynamicRendering; scissors.push_back(makeRect2D(0, 0, size.width + 1, size.height + 1)); params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, scissors))); params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH * 4, HEIGHT * 4, red))); testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_framebuffer_border_out", "", params)); } // Static oversized scissor, exceeds frame buffer and image attachment sizes { VkExtent2D size = { WIDTH / 2 - 1, HEIGHT / 2 - 1 }; TestParams params; params.framebufferSize = size; params.dynamicScissor = false; params.usesDynamicRendering = useDynamicRendering; params.staticScissors.push_back(makeRect2D(0, 0, WIDTH * 2, HEIGHT * 2)); params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH * 4, HEIGHT * 4, red))); testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_oversized", "", params)); } // Dynamic oversized scissor, exceeds frame buffer and image attachment sizes { VkExtent2D size = { WIDTH / 2 - 1, HEIGHT / 2 - 1 }; TestParams params; vector scissors; params.framebufferSize = size; params.dynamicScissor = true; params.usesDynamicRendering = useDynamicRendering; scissors.push_back(makeRect2D(0, 0, WIDTH * 2, HEIGHT * 2)); params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, scissors))); params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH * 4, HEIGHT * 4, red))); testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_oversized", "", params)); } } } // anonymous TestCaseGroup* createScissorTests (TestContext& testCtx, bool useDynamicRendering) { return createTestGroup(testCtx, "scissor", "Scissor tests", createTests, useDynamicRendering); } } // Draw } // vkt