blob: 876dc637e645765dfeace358295ebbf4b1364349 [file] [log] [blame]
/*-------------------------------------------------------------------------
* Vulkan Conformance Tests
* -----------------------------
*
* Copyright (c) 2020 Google Inc.
* Copyright (c) 2020 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 Tests for multiple color or depth clears within a render pass
*//*--------------------------------------------------------------------*/
#include "vktDrawMultipleClearsWithinRenderPass.hpp"
#include "vktTestGroupUtil.hpp"
#include "vktTestCaseUtil.hpp"
#include "vktDrawCreateInfoUtil.hpp"
#include "vktDrawBufferObjectUtil.hpp"
#include "vktDrawImageObjectUtil.hpp"
#include "vkPrograms.hpp"
#include "vkTypeUtil.hpp"
#include "vkRefUtil.hpp"
#include "vkCmdUtil.hpp"
#include "vkBuilderUtil.hpp"
#include "vkImageUtil.hpp"
#include "vkQueryUtil.hpp"
#include "tcuTextureUtil.hpp"
#include "tcuCommandLine.hpp"
#include "vktDrawTestCaseUtil.hpp"
#include "deStringUtil.hpp"
#include <cmath>
#include <vector>
#include <string>
#include <sstream>
namespace vkt
{
namespace Draw
{
namespace
{
using namespace vk;
using tcu::Vec4;
using de::SharedPtr;
using std::string;
using std::abs;
using std::vector;
using std::ostringstream;
const deUint32 WIDTH = 400;
const deUint32 HEIGHT = 300;
enum struct Topology
{
TRIANGLE_STRIP = 0,
TRIANGLES,
TRIANGLE
};
const Topology topologiesToTest[] =
{
Topology::TRIANGLE_STRIP,
Topology::TRIANGLES,
Topology::TRIANGLE
};
struct FormatPair
{
VkFormat colorFormat;
VkFormat depthFormat;
};
const FormatPair formatsToTest[] =
{
{ VK_FORMAT_R8G8B8A8_UNORM , VK_FORMAT_UNDEFINED },
{ VK_FORMAT_R8G8B8A8_SNORM , VK_FORMAT_UNDEFINED },
{ VK_FORMAT_UNDEFINED , VK_FORMAT_D32_SFLOAT },
{ VK_FORMAT_UNDEFINED , VK_FORMAT_D16_UNORM },
{ VK_FORMAT_R8G8B8A8_UNORM , VK_FORMAT_D32_SFLOAT },
{ VK_FORMAT_R8G8B8A8_UNORM , VK_FORMAT_D16_UNORM },
{ VK_FORMAT_R8G8B8A8_SNORM , VK_FORMAT_D32_SFLOAT },
{ VK_FORMAT_R8G8B8A8_SNORM , VK_FORMAT_D16_UNORM },
};
const Vec4 verticesTriangleStrip[] =
{
Vec4(-1.0f, -1.0f, 0.0f, 1.0f), // 0 -- 2
Vec4(-1.0f, 1.0f, 0.0f, 1.0f), // | / |
Vec4( 1.0f, -1.0f, 0.0f, 1.0f), // | / |
Vec4( 1.0f, 1.0f, 0.0f, 1.0f) // 1 -- 3
};
const Vec4 verticesTriangles[] =
{
Vec4(-1.0f, -1.0f, 0.0f, 1.0f), // 0 - 1
Vec4(-1.0f, 1.0f, 0.0f, 1.0f), // | /
Vec4( 1.0f, -1.0f, 0.0f, 1.0f), // 2
Vec4( 1.0f, -1.0f, 0.0f, 1.0f), // 4
Vec4(-1.0f, 1.0f, 0.0f, 1.0f), // / |
Vec4( 1.0f, 1.0f, 0.0f, 1.0f) // 3 - 5
};
const Vec4 verticesBigTriangle[] =
{
Vec4(-1.0f, -1.0f, 0.0f, 1.0f), // 0 - 2
Vec4(-1.0f, 3.0f, 0.0f, 1.0f), // | /
Vec4( 3.0f, -1.0f, 0.0f, 1.0f), // 1
};
const deUint32 TOPOLOGY_MAX_VERTICES_COUNT = 6;
const deUint32 TEST_MAX_STEPS_COUNT = 3;
struct Vertices
{
const char* testNameSuffix;
VkPrimitiveTopology topology;
deUint32 verticesCount;
const Vec4* vertices;
};
const Vertices verticesByTopology[] =
{
{
"_triangle_strip",
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
DE_LENGTH_OF_ARRAY(verticesTriangleStrip),
verticesTriangleStrip
},
{
"_triangles",
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
DE_LENGTH_OF_ARRAY(verticesTriangles),
verticesTriangles
},
{
"_big_triangle",
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
DE_LENGTH_OF_ARRAY(verticesBigTriangle),
verticesBigTriangle
}
};
enum struct ClearOp
{
LOAD = 0,
DRAW,
CLEAR
};
struct ClearStep
{
ClearOp clearOp;
Vec4 color;
float depth;
};
struct TestParams
{
VkFormat colorFormat;
VkFormat depthFormat;
Topology topology;
Vec4 expectedColor;
float colorEpsilon;
float expectedDepth;
float depthEpsilon;
deUint32 repeatCount;
bool enableBlend;
vector<ClearStep> steps;
};
class MultipleClearsTest : public TestInstance
{
public:
MultipleClearsTest (Context& context, const TestParams& params);
virtual tcu::TestStatus iterate (void);
private:
void clearAttachments (const DeviceInterface& vk, VkCommandBuffer cmdBuffer, const ClearOp clearOp, const size_t stepIndex);
SharedPtr<Image> m_colorTargetImage;
SharedPtr<Image> m_depthTargetImage;
Move<VkImageView> m_colorTargetView;
Move<VkImageView> m_depthTargetView;
SharedPtr<Buffer> m_vertexBuffer;
Move<VkRenderPass> m_renderPass;
Move<VkFramebuffer> m_framebuffer;
Move<VkPipelineLayout> m_pipelineLayout;
Move<VkPipeline> m_pipeline;
const TestParams m_params;
Vec4 m_vertices[TOPOLOGY_MAX_VERTICES_COUNT * TEST_MAX_STEPS_COUNT];
};
MultipleClearsTest::MultipleClearsTest (Context &context, const TestParams& params)
: TestInstance(context)
, m_params(params)
{
const DeviceInterface& vk = m_context.getDeviceInterface();
const VkDevice device = m_context.getDevice();
const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
const bool hasColor = m_params.colorFormat != VK_FORMAT_UNDEFINED;
const bool hasDepth = m_params.depthFormat != VK_FORMAT_UNDEFINED;
DescriptorSetLayoutBuilder descriptorSetLayoutBuilder;
// Vertex data
const auto& vertexData = verticesByTopology[(size_t)m_params.topology];
{
DE_ASSERT(vertexData.verticesCount <= TOPOLOGY_MAX_VERTICES_COUNT);
const size_t verticesCount = vertexData.verticesCount;
const VkDeviceSize dataSize = verticesCount * sizeof(Vec4);
const VkDeviceSize totalDataSize = m_params.steps.size() * dataSize;
DE_ASSERT(totalDataSize <= sizeof(m_vertices));
for(size_t i = 0; i < m_params.steps.size(); ++i)
{
const size_t start = i * verticesCount;
deMemcpy(&m_vertices[start], vertexData.vertices, static_cast<size_t>(dataSize));
for(size_t j = 0; j < verticesCount; ++j)
m_vertices[start + j][2] = m_params.steps[i].depth;
}
m_vertexBuffer = Buffer::createAndAlloc(vk, device, BufferCreateInfo(totalDataSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
m_context.getDefaultAllocator(), MemoryRequirement::HostVisible);
deMemcpy(m_vertexBuffer->getBoundMemory().getHostPtr(), m_vertices, static_cast<std::size_t>(totalDataSize));
flushMappedMemoryRange(vk, device, m_vertexBuffer->getBoundMemory().getMemory(), m_vertexBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
}
// Render pass
std::vector<VkImageView> attachments;
{
RenderPassCreateInfo renderPassCreateInfo;
if (hasColor)
{
const VkImageUsageFlags targetImageUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
const ImageCreateInfo targetImageCreateInfo (VK_IMAGE_TYPE_2D, m_params.colorFormat, { WIDTH, HEIGHT, 1u }, 1u, 1u, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_TILING_OPTIMAL, targetImageUsageFlags);
m_colorTargetImage = Image::createAndAlloc(vk, device, targetImageCreateInfo, m_context.getDefaultAllocator(), queueFamilyIndex);
renderPassCreateInfo.addAttachment(AttachmentDescription(
m_params.colorFormat, // format
VK_SAMPLE_COUNT_1_BIT, // samples
VK_ATTACHMENT_LOAD_OP_LOAD, // loadOp
VK_ATTACHMENT_STORE_OP_STORE, // storeOp
VK_ATTACHMENT_LOAD_OP_DONT_CARE, // stencilLoadOp
VK_ATTACHMENT_STORE_OP_DONT_CARE, // stencilStoreOp
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // initialLayout
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)); // finalLayout
const ImageViewCreateInfo colorTargetViewInfo (m_colorTargetImage->object(), VK_IMAGE_VIEW_TYPE_2D, m_params.colorFormat);
m_colorTargetView = createImageView(vk, device, &colorTargetViewInfo);
attachments.push_back(*m_colorTargetView);
}
if (hasDepth)
{
const VkImageUsageFlags depthImageUsageFlags = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
const ImageCreateInfo depthImageCreateInfo (VK_IMAGE_TYPE_2D, m_params.depthFormat, { WIDTH, HEIGHT, 1u }, 1u, 1u, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_TILING_OPTIMAL, depthImageUsageFlags);
m_depthTargetImage = Image::createAndAlloc(vk, device, depthImageCreateInfo, m_context.getDefaultAllocator(), queueFamilyIndex);
renderPassCreateInfo.addAttachment(AttachmentDescription(
m_params.depthFormat, // format
VK_SAMPLE_COUNT_1_BIT, // samples
VK_ATTACHMENT_LOAD_OP_LOAD, // loadOp
VK_ATTACHMENT_STORE_OP_STORE, // storeOp
VK_ATTACHMENT_LOAD_OP_DONT_CARE, // stencilLoadOp
VK_ATTACHMENT_STORE_OP_DONT_CARE, // stencilStoreOp
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // initialLayout
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)); // finalLayout
const ImageViewCreateInfo depthTargetViewInfo (m_depthTargetImage->object(), VK_IMAGE_VIEW_TYPE_2D, m_params.depthFormat);
m_depthTargetView = createImageView(vk, device, &depthTargetViewInfo);
attachments.push_back(*m_depthTargetView);
}
const VkAttachmentReference colorAttachmentReference = hasColor ? makeAttachmentReference(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) : AttachmentReference();
const VkAttachmentReference depthAttachmentReference = hasDepth ? makeAttachmentReference(hasColor ? 1u : 0u, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) : AttachmentReference();
renderPassCreateInfo.addSubpass(SubpassDescription(
VK_PIPELINE_BIND_POINT_GRAPHICS, // pipelineBindPoint
(VkSubpassDescriptionFlags)0, // flags
0u, // inputAttachmentCount
DE_NULL, // inputAttachments
hasColor ? 1 : 0, // colorAttachmentCount
hasColor ? &colorAttachmentReference : DE_NULL, // colorAttachments
DE_NULL, // resolveAttachments
depthAttachmentReference, // depthStencilAttachment
0u, // preserveAttachmentCount
DE_NULL)); // preserveAttachments
m_renderPass = createRenderPass(vk, device, &renderPassCreateInfo);
}
const FramebufferCreateInfo framebufferCreateInfo (*m_renderPass, attachments, WIDTH, HEIGHT, 1);
m_framebuffer = createFramebuffer(vk, device, &framebufferCreateInfo);
// Vertex input
const VkVertexInputBindingDescription vertexInputBindingDescription =
{
0u, // uint32_t binding;
sizeof(Vec4), // uint32_t stride;
VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate;
};
const VkVertexInputAttributeDescription vertexInputAttributeDescription =
{
0u, // uint32_t location;
0u, // uint32_t binding;
VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
0u // uint32_t offset;
};
const PipelineCreateInfo::VertexInputState vertexInputState = PipelineCreateInfo::VertexInputState(1, &vertexInputBindingDescription,
1, &vertexInputAttributeDescription);
// Graphics pipeline
const Unique<VkShaderModule> vertexModule (createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0));
const Unique<VkShaderModule> fragmentModule (createShaderModule(vk, device, m_context.getBinaryCollection().get(hasColor ? "frag" : "frag_depthonly"), 0));
const VkPushConstantRange pcRange = vk::VkPushConstantRange { VkShaderStageFlagBits::VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ClearStep::color) };
const PipelineLayoutCreateInfo pipelineLayoutCreateInfo (0u, DE_NULL, 1u, &pcRange);
m_pipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
const VkRect2D scissor = makeRect2D(WIDTH, HEIGHT);
const VkViewport viewport = makeViewport(WIDTH, HEIGHT);
const auto vkCbAttachmentState = makePipelineColorBlendAttachmentState(
m_params.enableBlend ? VK_TRUE : VK_FALSE, // VkBool32 blendEnable
VK_BLEND_FACTOR_SRC_ALPHA, // VkBlendFactor srcColorBlendFactor
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, // VkBlendFactor dstColorBlendFactor
VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp
VK_BLEND_FACTOR_ZERO, // VkBlendFactor srcAlphaBlendFactor
VK_BLEND_FACTOR_ONE, // VkBlendFactor dstAlphaBlendFactor
VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp
VK_COLOR_COMPONENT_R_BIT | // VkColorComponentFlags colorWriteMask
VK_COLOR_COMPONENT_G_BIT |
VK_COLOR_COMPONENT_B_BIT |
VK_COLOR_COMPONENT_A_BIT);
PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, (VkPipelineCreateFlags)0);
pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vertexModule, "main", VK_SHADER_STAGE_VERTEX_BIT));
pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fragmentModule, "main", VK_SHADER_STAGE_FRAGMENT_BIT));
pipelineCreateInfo.addState (PipelineCreateInfo::VertexInputState (vertexInputState));
pipelineCreateInfo.addState (PipelineCreateInfo::InputAssemblerState(vertexData.topology));
pipelineCreateInfo.addState (PipelineCreateInfo::ColorBlendState (1, &vkCbAttachmentState));
pipelineCreateInfo.addState (PipelineCreateInfo::ViewportState (1, std::vector<VkViewport>(1, viewport), std::vector<VkRect2D>(1, scissor)));
pipelineCreateInfo.addState (PipelineCreateInfo::DepthStencilState (hasDepth, hasDepth, VK_COMPARE_OP_ALWAYS, VK_FALSE, VK_FALSE));
pipelineCreateInfo.addState (PipelineCreateInfo::RasterizerState ());
pipelineCreateInfo.addState (PipelineCreateInfo::MultiSampleState ());
m_pipeline = createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo);
}
void MultipleClearsTest::clearAttachments (const DeviceInterface& vk, vk::VkCommandBuffer cmdBuffer, const ClearOp clearOp, const size_t stepIndex)
{
const Vec4& color = m_params.steps[stepIndex].color;
const float depth = m_params.steps[stepIndex].depth;
switch(clearOp) {
case ClearOp::LOAD:
break;
case ClearOp::DRAW:
{
const auto& vertexData = verticesByTopology[(size_t)m_params.topology];
const deUint32 verticesCount = vertexData.verticesCount;
vk.cmdPushConstants(cmdBuffer, *m_pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(color), color.getPtr());
vk.cmdDraw(cmdBuffer, verticesCount, 1, static_cast<deUint32>(verticesCount * stepIndex), 0);
}
break;
case ClearOp::CLEAR:
{
vector<VkClearAttachment> clearAttachments;
if (m_params.colorFormat != VK_FORMAT_UNDEFINED)
{
const VkClearAttachment clearAttachment =
{
VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask
static_cast<deUint32>(clearAttachments.size()), // uint32_t colorAttachment
makeClearValueColor(color) // VkClearValue clearValue
};
clearAttachments.push_back(clearAttachment);
}
if (m_params.depthFormat != VK_FORMAT_UNDEFINED)
{
const VkClearAttachment clearAttachment =
{
VK_IMAGE_ASPECT_DEPTH_BIT, // VkImageAspectFlags aspectMask
static_cast<deUint32>(clearAttachments.size()), // uint32_t colorAttachment
makeClearValueDepthStencil(depth, 0) // VkClearValue clearValue
};
clearAttachments.push_back(clearAttachment);
}
const VkClearRect clearRect =
{
makeRect2D(WIDTH, HEIGHT), // VkRect2D rect
0, // uint32_t baseArrayLayer
1 // uint32_t layerCount
};
vk.cmdClearAttachments(cmdBuffer, static_cast<deUint32>(clearAttachments.size()), clearAttachments.data(), 1, &clearRect);
}
break;
default:
break;
}
}
tcu::TestStatus MultipleClearsTest::iterate (void)
{
const DeviceInterface& vk = m_context.getDeviceInterface();
const VkDevice device = m_context.getDevice();
const VkQueue queue = m_context.getUniversalQueue();
const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
const CmdPoolCreateInfo cmdPoolCreateInfo (queueFamilyIndex);
const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, &cmdPoolCreateInfo));
const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
const bool hasColor = m_params.colorFormat != VK_FORMAT_UNDEFINED;
const bool hasDepth = m_params.depthFormat != VK_FORMAT_UNDEFINED;
beginCommandBuffer(vk, *cmdBuffer);
if (hasColor)
initialTransitionColor2DImage(vk, *cmdBuffer, m_colorTargetImage->object(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
if (hasDepth)
initialTransitionDepth2DImage(vk, *cmdBuffer, m_depthTargetImage->object(), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
if (!m_params.steps.empty() && m_params.steps[0].clearOp == ClearOp::LOAD)
beginRenderPass(vk, *cmdBuffer, *m_renderPass, *m_framebuffer, makeRect2D(0, 0, WIDTH, HEIGHT), m_params.steps[0].color, m_params.steps[0].depth, 0);
else
beginRenderPass(vk, *cmdBuffer, *m_renderPass, *m_framebuffer, makeRect2D(0, 0, WIDTH, HEIGHT));
vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
{
const VkDeviceSize offset = 0;
const VkBuffer buffer = m_vertexBuffer->object();
vk.cmdBindVertexBuffers(*cmdBuffer, 0, 1, &buffer, &offset);
}
for(deUint32 i = 0; i < m_params.repeatCount; ++i)
for(size_t j = 0; j < m_params.steps.size(); ++j)
{
const auto& step = m_params.steps[j];
// ClearOp::LOAD only supported for first step
DE_ASSERT(j == 0 || step.clearOp != ClearOp::LOAD);
clearAttachments(vk, *cmdBuffer, step.clearOp, j);
}
endRenderPass(vk, *cmdBuffer);
if (hasDepth)
{
const VkMemoryBarrier memBarrier = { VK_STRUCTURE_TYPE_MEMORY_BARRIER, DE_NULL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT };
vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, 0, 1, &memBarrier, 0, DE_NULL, 0, DE_NULL);
}
if (hasColor)
{
const VkMemoryBarrier memBarrier = { VK_STRUCTURE_TYPE_MEMORY_BARRIER, DE_NULL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT };
vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 1, &memBarrier, 0, DE_NULL, 0, DE_NULL);
}
if (hasColor)
transition2DImage(vk, *cmdBuffer, m_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_MEMORY_READ_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_HOST_BIT);
if (hasDepth)
transition2DImage(vk, *cmdBuffer, m_depthTargetImage->object(), VK_IMAGE_ASPECT_DEPTH_BIT,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_ACCESS_MEMORY_READ_BIT,
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_HOST_BIT);
endCommandBuffer(vk, *cmdBuffer);
submitCommandsAndWait(vk, device, queue, *cmdBuffer);
VK_CHECK(vk.queueWaitIdle(queue));
if (hasColor)
{
const auto resultImage = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, { 0, 0, 0 }, WIDTH, HEIGHT, VK_IMAGE_ASPECT_COLOR_BIT);
#ifdef CTS_USES_VULKANSC
if (m_context.getTestContext().getCommandLine().isSubProcess())
#endif // CTS_USES_VULKANSC
{
for(int z = 0; z < resultImage.getDepth(); ++z)
for(int y = 0; y < resultImage.getHeight(); ++y)
for(int x = 0; x < resultImage.getWidth(); ++x)
{
const Vec4 difference = m_params.expectedColor - resultImage.getPixel(x,y,z);
if (abs(difference.x()) >= m_params.colorEpsilon || abs(difference.y()) >= m_params.colorEpsilon || abs(difference.z()) >= m_params.colorEpsilon)
{
ostringstream msg;
msg << "Color value mismatch, expected: " << m_params.expectedColor << ", got: " << resultImage.getPixel(x,y,z) << " at " << "(" << x << ", " << y << ", " << z << ")";
return tcu::TestStatus::fail(msg.str());
}
}
}
}
if (hasDepth)
{
const auto resultImage = m_depthTargetImage->readSurface(queue, m_context.getDefaultAllocator(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, { 0, 0, 0 }, WIDTH, HEIGHT, VK_IMAGE_ASPECT_DEPTH_BIT);
#ifdef CTS_USES_VULKANSC
if (m_context.getTestContext().getCommandLine().isSubProcess())
#endif // CTS_USES_VULKANSC
{
for(int z = 0; z < resultImage.getDepth(); ++z)
for(int y = 0; y < resultImage.getHeight(); ++y)
for(int x = 0; x < resultImage.getWidth(); ++x)
{
const float difference = m_params.expectedDepth - resultImage.getPixDepth(x,y,z);
if (abs(difference) >= m_params.depthEpsilon)
{
ostringstream msg;
msg << "Depth value mismatch, expected: " << m_params.expectedDepth << ", got: " << resultImage.getPixDepth(x,y,z) << " at " << "(" << x << ", " << y << ", " << z << ")";
return tcu::TestStatus::fail(msg.str());
}
}
}
}
return tcu::TestStatus::pass("Pass");
}
class MultipleClearsWithinRenderPassTest : public TestCase
{
public:
MultipleClearsWithinRenderPassTest (tcu::TestContext& testCtx, const string& name, const string& description, const TestParams& params)
: TestCase(testCtx, name, description)
, m_params(params)
{
DE_ASSERT(m_params.steps.size() <= static_cast<size_t>(TEST_MAX_STEPS_COUNT));
}
virtual void initPrograms (SourceCollections& programCollection) const
{
{
ostringstream src;
src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
<< "\n"
<< "layout(location = 0) in vec4 in_position;\n"
<< "\n"
<< "out gl_PerVertex {\n"
<< " vec4 gl_Position;\n"
<< "};\n"
<< "\n"
<< "void main(void)\n"
<< "{\n"
<< " gl_Position = in_position;\n"
<< "}\n";
programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
}
{
ostringstream src;
src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
<< "\n"
<< "layout(push_constant) uniform Color { vec4 color; } u_color;\n"
<< "layout(location = 0) out vec4 out_color;\n"
<< "\n"
<< "void main(void)\n"
<< "{\n"
<< " out_color = u_color.color;\n"
<< "}\n";
programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
}
{
ostringstream src;
src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
<< "\n"
<< "layout(push_constant) uniform Color { vec4 color; } u_color;\n"
<< "\n"
<< "void main(void)\n"
<< "{\n"
<< "}\n";
programCollection.glslSources.add("frag_depthonly") << glu::FragmentSource(src.str());
}
}
virtual void checkSupport (Context& context) const
{
VkImageFormatProperties imageFormatProperties;
const auto& vki = context.getInstanceInterface();
const auto& vkd = context.getPhysicalDevice();
if (m_params.colorFormat != VK_FORMAT_UNDEFINED)
{
const auto colorUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
if (vki.getPhysicalDeviceImageFormatProperties(vkd, m_params.colorFormat, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, colorUsage, 0u, &imageFormatProperties) != VK_SUCCESS)
TCU_THROW(NotSupportedError, "Color format not supported");
}
if (m_params.depthFormat != VK_FORMAT_UNDEFINED)
{
const auto depthUsage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
if (vki.getPhysicalDeviceImageFormatProperties(vkd, m_params.depthFormat, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, depthUsage, 0u, &imageFormatProperties) != VK_SUCCESS)
TCU_THROW(NotSupportedError, "Depth format not supported");
}
}
virtual TestInstance* createInstance (Context& context) const
{
return new MultipleClearsTest(context, m_params);
}
private:
const TestParams m_params;
};
} // anonymous
MultipleClearsWithinRenderPassTests::MultipleClearsWithinRenderPassTests (tcu::TestContext &testCtx)
: TestCaseGroup (testCtx, "multiple_clears_within_render_pass", "Tests for multiple clears within render pass")
{
}
MultipleClearsWithinRenderPassTests::~MultipleClearsWithinRenderPassTests ()
{
}
void MultipleClearsWithinRenderPassTests::init ()
{
for(const auto &formatPair : formatsToTest)
{
ostringstream formatSuffix;
if (formatPair.colorFormat != VK_FORMAT_UNDEFINED)
formatSuffix << "_c" << de::toLower(string(getFormatName(formatPair.colorFormat)).substr(9));
if (formatPair.depthFormat != VK_FORMAT_UNDEFINED)
formatSuffix << "_d" << de::toLower(string(getFormatName(formatPair.depthFormat)).substr(9));
for(const auto &topology : topologiesToTest)
{
const string testNameSuffix = formatSuffix.str() + verticesByTopology[(deUint32)topology].testNameSuffix;
{
const TestParams params =
{
formatPair.colorFormat, // VkFormat colorFormat;
formatPair.depthFormat, // VkFormat depthFormat;
topology, // Topology topology;
Vec4(0.0f, 0.5f, 0.5f, 1.0f), // Vec4 expectedColor;
0.01f, // float colorEpsilon;
0.9f, // float expectedDepth;
0.01f, // float depthEpsilon;
1u, // deUint32 repeatCount;
true, // bool enableBlend;
{ // vector<ClearStep> steps;
{ ClearOp::LOAD , Vec4(1.0f, 0.0f, 0.0f, 1.0f) , 0.7f },
{ ClearOp::CLEAR , Vec4(0.0f, 1.0f, 0.0f, 1.0f) , 0.3f },
{ ClearOp::DRAW , Vec4(0.0f, 0.0f, 1.0f, 0.5f) , 0.9f }
}
};
addChild(new MultipleClearsWithinRenderPassTest(m_testCtx, "load_clear_draw" + testNameSuffix, "Multiple clears within same render pass, methods: load, clear, draw", params));
}
{
const TestParams params =
{
formatPair.colorFormat, // VkFormat format;
formatPair.depthFormat, // VkFormat depthFormat;
topology, // Topology topology;
Vec4(0.0f, 0.5f, 0.5f, 1.0f), // Vec4 expectedColor;
0.01f, // float colorEpsilon;
0.9f, // float expectedDepth;
0.01f, // float depthEpsilon;
1u, // deUint32 repeatCount;
true, // bool enableBlend;
{ // vector<ClearStep> steps;
{ ClearOp::DRAW , Vec4(1.0f, 0.0f, 0.0f, 1.0f) , 0.7f },
{ ClearOp::CLEAR , Vec4(0.0f, 1.0f, 0.0f, 1.0f) , 0.3f },
{ ClearOp::DRAW , Vec4(0.0f, 0.0f, 1.0f, 0.5f) , 0.9f }
}
};
addChild(new MultipleClearsWithinRenderPassTest(m_testCtx, "draw_clear_draw" + testNameSuffix, "Multiple clears within same render pass, methods: draw, clear, draw", params));
}
{
const TestParams params =
{
formatPair.colorFormat, // VkFormat format;
formatPair.depthFormat, // VkFormat depthFormat;
topology, // Topology topology;
Vec4(0.0f, 0.5f, 0.5f, 1.0f), // Vec4 expectedColor;
0.01f, // float colorEpsilon;
0.9f, // float expectedDepth;
0.01f, // float depthEpsilon;
1u, // deUint32 repeatCount;
true, // bool enableBlend;
{ // vector<ClearStep> steps;
{ ClearOp::CLEAR , Vec4(1.0f, 0.0f, 0.0f, 1.0f) , 0.7f },
{ ClearOp::CLEAR , Vec4(0.0f, 1.0f, 0.0f, 1.0f) , 0.3f },
{ ClearOp::DRAW , Vec4(0.0f, 0.0f, 1.0f, 0.5f) , 0.9f }
}
};
addChild(new MultipleClearsWithinRenderPassTest(m_testCtx, "clear_clear_draw" + testNameSuffix, "Multiple clears within same render pass, methods: clear, clear, draw", params));
}
{
const TestParams params =
{
formatPair.colorFormat, // VkFormat format;
formatPair.depthFormat, // VkFormat depthFormat;
topology, // Topology topology;
Vec4(0.0f, 1.0f, 0.0f, 1.0f), // Vec4 expectedColor;
0.01f, // float colorEpsilon;
0.9f, // float expectedDepth;
0.01f, // float depthEpsilon;
1u, // deUint32 repeatCount;
false, // bool enableBlend;
{ // vector<ClearStep> steps;
{ ClearOp::LOAD , Vec4(1.0f, 0.0f, 0.0f, 1.0f) , 0.3f },
{ ClearOp::CLEAR , Vec4(0.0f, 1.0f, 0.0f, 1.0f) , 0.9f }
}
};
addChild(new MultipleClearsWithinRenderPassTest(m_testCtx, "load_clear" + testNameSuffix, "Multiple clears within same render pass, methods: load, clear", params));
}
{
const TestParams params =
{
formatPair.colorFormat, // VkFormat format;
formatPair.depthFormat, // VkFormat depthFormat;
topology, // Topology topology;
Vec4(0.0f, 1.0f, 0.0f, 1.0f), // Vec4 expectedColor;
0.01f, // float colorEpsilon;
0.9f, // float expectedDepth;
0.01f, // float depthEpsilon;
1u, // deUint32 repeatCount;
false, // bool enableBlend;
{ // vector<ClearStep> steps;
{ ClearOp::DRAW , Vec4(1.0f, 0.0f, 0.0f, 1.0f) , 0.3f },
{ ClearOp::CLEAR , Vec4(0.0f, 1.0f, 0.0f, 1.0f) , 0.9f }
}
};
addChild(new MultipleClearsWithinRenderPassTest(m_testCtx, "draw_clear" + testNameSuffix, "Multiple clears within same render pass, methods: draw, clear", params));
}
{
const TestParams params =
{
formatPair.colorFormat, // VkFormat format;
formatPair.depthFormat, // VkFormat depthFormat;
topology, // Topology topology;
Vec4(0.0f, 1.0f, 0.0f, 1.0f), // Vec4 expectedColor;
0.01f, // float colorEpsilon;
0.9f, // float expectedDepth;
0.01f, // float depthEpsilon;
1u, // deUint32 repeatCount;
false, // bool enableBlend;
{ // vector<ClearStep> steps;
{ ClearOp::CLEAR , Vec4(1.0f, 0.0f, 0.0f, 1.0f) , 0.3f },
{ ClearOp::CLEAR , Vec4(0.0f, 1.0f, 0.0f, 1.0f) , 0.9f }
}
};
addChild(new MultipleClearsWithinRenderPassTest(m_testCtx, "clear_clear" + testNameSuffix, "Multiple clears within same render pass, methods: clear, clear", params));
}
}
}
}
} // Draw
} // vkt