blob: 05ecb6a95f2928d3a0ef7f819517e3b5e9175fa8 [file] [log] [blame]
/*------------------------------------------------------------------------
* 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 <string>
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)
{
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)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)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<PositionColorVertex> getVertices (deUint32 offset) { DE_UNREF(offset); return vector<PositionColorVertex>(); }
virtual void addCommands (const DeviceInterface& vk, VkCommandBuffer cmdBuffer) = 0;
virtual deUint32 getMaxScissor (void) { return 0; }
virtual vector<ColorQuad> getQuad (void) { return vector<ColorQuad>(); }
virtual vector<VkRect2D> updateScissors (vector<VkRect2D> scissors) { return scissors; }
virtual bool isScissored (void) { return false; }
private:
};
typedef de::SharedPtr<TestCommand> TestCommandSp;
class QuadDrawTestCommand : public TestCommand
{
public:
QuadDrawTestCommand (deUint32 x, deUint32 y, deUint32 width, deUint32 height, Vec4 color);
virtual ~QuadDrawTestCommand (void) {}
virtual vector<PositionColorVertex> getVertices (deUint32 offset);
virtual void addCommands (const DeviceInterface& vk, VkCommandBuffer cmdBuffer);
virtual vector<ColorQuad> getQuad (void) { return vector<ColorQuad>(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_quad(x, y, width, height, color)
{
}
vector<PositionColorVertex> QuadDrawTestCommand::getVertices (deUint32 offset)
{
vector<PositionColorVertex> 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<ColorQuad> getQuad (void) { return vector<ColorQuad>(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<VkRect2D> 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<VkRect2D> updateScissors (vector<VkRect2D> scissors);
private:
deUint32 m_firstScissor;
vector<VkRect2D> m_scissors;
};
DynamicScissorTestCommand::DynamicScissorTestCommand (deUint32 firstScissor, vector<VkRect2D> 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<VkRect2D> DynamicScissorTestCommand::updateScissors (vector<VkRect2D> 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
{
bool dynamicScissor;
vector<VkRect2D> staticScissors;
vector<TestCommandSp> commands;
bool usesMultipleScissors;
};
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.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;
de::SharedPtr<Image> 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<VkCommandPool> cmdPool = createCommandPool(vk, device, &cmdPoolCreateInfo);
Move<VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
const Unique<VkShaderModule> vs (createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0));
Move<VkShaderModule> gs;
const Unique<VkShaderModule> fs (createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0));
const deUint32 numScissors = countScissors(m_params);
VkDeviceSize vertexBufferSize = 0;
de::SharedPtr<Buffer> vertexBuffer;
Move<VkRenderPass> renderPass;
Move<VkImageView> colorTargetView;
Move<VkFramebuffer> framebuffer;
Move<VkPipeline> pipeline;
TextureLevel refImage;
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, VK_FORMAT_R8G8B8A8_UNORM, targetImageExtent, 1, 1, VK_SAMPLE_COUNT_1_BIT,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
colorTargetImage = Image::createAndAlloc(vk, device, targetImageCreateInfo, m_context.getDefaultAllocator(), m_context.getUniversalQueueFamilyIndex());
}
// Create render pass and frame buffer
{
const ImageViewCreateInfo colorTargetViewInfo (colorTargetImage->object(), VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_R8G8B8A8_UNORM);
colorTargetView = createImageView(vk, device, &colorTargetViewInfo);
RenderPassCreateInfo renderPassCreateInfo;
renderPassCreateInfo.addAttachment(AttachmentDescription(VK_FORMAT_R8G8B8A8_UNORM,
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_UNDEFINED,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
const VkAttachmentReference colorAttachmentRef = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
vector<VkImageView> colorAttachment (1, *colorTargetView);
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);
const FramebufferCreateInfo framebufferCreateInfo (*renderPass, colorAttachment, WIDTH, HEIGHT, 1);
framebuffer = createFramebuffer(vk, device, &framebufferCreateInfo);
}
// Create vertex buffer
{
vector<PositionColorVertex> vertices;
for (size_t commandIdx = 0; commandIdx < m_params.commands.size(); commandIdx++)
{
vector<PositionColorVertex> 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<deUint8*>(vertexBuffer->getBoundMemory().getHostPtr());
deMemcpy(ptr, vertices.data(), static_cast<size_t>(vertexBufferSize));
flushMappedMemoryRange(vk, device, vertexBuffer->getBoundMemory().getMemory(), vertexBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
}
}
const PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
Move<VkPipelineLayout> 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<VkDynamicState>(1, VK_DYNAMIC_STATE_SCISSOR)));
pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(numScissors, vector<VkViewport>(numScissors, viewport), vector<VkRect2D>(numScissors, makeRect2D(0, 0))));
}
else
{
pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(numScissors, vector<VkViewport>(numScissors, viewport), m_params.staticScissors));
}
pipeline = createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo);
}
// Queue commands and read results.
{
const ImageSubresourceRange subresourceRange (VK_IMAGE_ASPECT_COLOR_BIT);
const VkRect2D renderArea = makeRect2D(WIDTH, HEIGHT);
const VkDeviceSize vertexBufferOffset = 0;
const VkOffset3D zeroOffset = { 0, 0, 0 };
const Vec4 clearColor (0.0f, 0.0f, 0.0f, 1.0f);
beginCommandBuffer(vk, *cmdBuffer, 0u);
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);
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<VkRect2D> scissors = m_params.staticScissors;
for (size_t commandIdx = 0; commandIdx < m_params.commands.size(); commandIdx++)
{
scissors = m_params.commands[commandIdx]->updateScissors(scissors);
vector<ColorQuad> 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]) : 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)
{
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.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.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.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.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.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.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.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;
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.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.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(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.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(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<VkRect2D>(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<VkRect2D> scissors;
params.dynamicScissor = true;
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<VkRect2D> scissors;
params.dynamicScissor = true;
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<VkRect2D>(1, scissors[2]))));
params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(1, vector<VkRect2D>(1, scissors[1]))));
params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(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<VkRect2D>(1, scissors[1]))));
params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, scissors[0]))));
params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(2, vector<VkRect2D>(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.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(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.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(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.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(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.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(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<VkRect2D> scissors;
params.dynamicScissor = true;
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.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(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<VkRect2D> scissors;
params.dynamicScissor = true;
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<VkRect2D>(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));
}
}
} // anonymous
TestCaseGroup* createScissorTests (TestContext& testCtx)
{
return createTestGroup(testCtx, "scissor", "Scissor tests", createTests);
}
} // Draw
} // vkt