blob: d2eda97e4c9553814d97d23e2897ca90457a7cf4 [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;
const SharedGroupParams groupParams;
vector<ClearStep> steps;
};
class MultipleClearsTest : public TestInstance
{
public:
MultipleClearsTest (Context& context, const TestParams& params);
virtual tcu::TestStatus iterate (void);
private:
void preRenderCommands (VkCommandBuffer cmdBuffer) const;
void beginLegacyRender (VkCommandBuffer cmdBuffer) const;
void drawCommands (VkCommandBuffer cmdBuffer) const;
#ifndef CTS_USES_VULKANSC
void beginSecondaryCmdBuffer (VkCommandBuffer cmdBuffer, VkRenderingFlagsKHR renderingFlags = 0u) const;
void beginDynamicRender (VkCommandBuffer cmdBuffer, VkRenderingFlagsKHR renderingFlags = 0u) const;
#endif // CTS_USES_VULKANSC
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);
}
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);
const ImageViewCreateInfo colorTargetViewInfo (m_colorTargetImage->object(), VK_IMAGE_VIEW_TYPE_2D, m_params.colorFormat);
m_colorTargetView = createImageView(vk, device, &colorTargetViewInfo);
}
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);
const ImageViewCreateInfo depthTargetViewInfo (m_depthTargetImage->object(), VK_IMAGE_VIEW_TYPE_2D, m_params.depthFormat);
m_depthTargetView = createImageView(vk, device, &depthTargetViewInfo);
}
// Render pass
if (!m_params.groupParams->useDynamicRendering)
{
RenderPassCreateInfo renderPassCreateInfo;
if (hasColor)
{
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
}
if (hasDepth)
{
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 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);
std::vector<VkImageView> attachments;
if (hasColor)
attachments.push_back(*m_colorTargetView);
if (hasDepth)
attachments.push_back(*m_depthTargetView);
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 ());
#ifndef CTS_USES_VULKANSC
vk::VkPipelineRenderingCreateInfoKHR renderingCreateInfo
{
VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR,
DE_NULL,
0u,
hasColor,
(hasColor ? &m_params.colorFormat : DE_NULL),
m_params.depthFormat,
m_params.depthFormat
};
if (m_params.groupParams->useDynamicRendering)
pipelineCreateInfo.pNext = &renderingCreateInfo;
#endif // CTS_USES_VULKANSC
m_pipeline = createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo);
}
void MultipleClearsTest::preRenderCommands(VkCommandBuffer cmdBuffer) const
{
const DeviceInterface& vk = m_context.getDeviceInterface();
if (m_params.colorFormat)
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 (m_params.depthFormat)
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);
}
void MultipleClearsTest::beginLegacyRender(VkCommandBuffer cmdBuffer) const
{
const DeviceInterface& vk = m_context.getDeviceInterface();
const VkRect2D renderArea = makeRect2D(0, 0, WIDTH, HEIGHT);
if (!m_params.steps.empty() && m_params.steps[0].clearOp == ClearOp::LOAD)
beginRenderPass(vk, cmdBuffer, *m_renderPass, *m_framebuffer, renderArea, m_params.steps[0].color, m_params.steps[0].depth, 0);
else
beginRenderPass(vk, cmdBuffer, *m_renderPass, *m_framebuffer, renderArea);
}
void MultipleClearsTest::drawCommands(vk::VkCommandBuffer cmdBuffer) const
{
const DeviceInterface& vk = m_context.getDeviceInterface();
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 stepIndex = 0; stepIndex < m_params.steps.size(); ++stepIndex)
{
const auto& step = m_params.steps[stepIndex];
// ClearOp::LOAD only supported for first step
DE_ASSERT(stepIndex == 0 || step.clearOp != ClearOp::LOAD);
const Vec4& color = step.color;
const float depth = step.depth;
switch(step.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;
}
}
}
#ifndef CTS_USES_VULKANSC
void MultipleClearsTest::beginSecondaryCmdBuffer(VkCommandBuffer cmdBuffer, VkRenderingFlagsKHR renderingFlags) const
{
VkCommandBufferInheritanceRenderingInfoKHR inheritanceRenderingInfo
{
VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR, // VkStructureType sType;
DE_NULL, // const void* pNext;
renderingFlags, // VkRenderingFlagsKHR flags;
0u, // uint32_t viewMask;
(m_params.colorFormat != VK_FORMAT_UNDEFINED), // uint32_t colorAttachmentCount;
&m_params.colorFormat, // const VkFormat* pColorAttachmentFormats;
m_params.depthFormat, // VkFormat depthAttachmentFormat;
VK_FORMAT_UNDEFINED, // VkFormat stencilAttachmentFormat;
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples;
};
const VkCommandBufferInheritanceInfo bufferInheritanceInfo = initVulkanStructure(&inheritanceRenderingInfo);
VkCommandBufferUsageFlags usageFlags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
usageFlags |= VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
const VkCommandBufferBeginInfo commandBufBeginParams
{
VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
usageFlags, // VkCommandBufferUsageFlags flags;
&bufferInheritanceInfo
};
const DeviceInterface& vk = m_context.getDeviceInterface();
VK_CHECK(vk.beginCommandBuffer(cmdBuffer, &commandBufBeginParams));
}
void MultipleClearsTest::beginDynamicRender(VkCommandBuffer cmdBuffer, VkRenderingFlagsKHR renderingFlags) const
{
const DeviceInterface& vk = m_context.getDeviceInterface();
const VkRect2D renderArea = makeRect2D(0, 0, WIDTH, HEIGHT);
VkClearValue clearColorValue = makeClearValueColor(tcu::Vec4(0.0f));
VkClearValue clearDepthValue = makeClearValueDepthStencil(0.0f, 0u);
if (!m_params.steps.empty() && m_params.steps[0].clearOp == ClearOp::LOAD)
{
clearColorValue = makeClearValueColor(m_params.steps[0].color);
clearDepthValue = makeClearValueDepthStencil(m_params.steps[0].depth, 0u);
}
vk::VkRenderingAttachmentInfoKHR colorAttachment
{
vk::VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR, // VkStructureType sType;
DE_NULL, // const void* pNext;
*m_colorTargetView, // VkImageView imageView;
vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout imageLayout;
vk::VK_RESOLVE_MODE_NONE, // VkResolveModeFlagBits resolveMode;
DE_NULL, // VkImageView resolveImageView;
vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout resolveImageLayout;
vk::VK_ATTACHMENT_LOAD_OP_LOAD, // VkAttachmentLoadOp loadOp;
vk::VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
clearColorValue // VkClearValue clearValue;
};
vk::VkRenderingAttachmentInfoKHR depthAttachment
{
vk::VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR, // VkStructureType sType;
DE_NULL, // const void* pNext;
*m_depthTargetView, // VkImageView imageView;
vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout imageLayout;
vk::VK_RESOLVE_MODE_NONE, // VkResolveModeFlagBits resolveMode;
DE_NULL, // VkImageView resolveImageView;
vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout resolveImageLayout;
vk::VK_ATTACHMENT_LOAD_OP_LOAD, // VkAttachmentLoadOp loadOp;
vk::VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
clearDepthValue // VkClearValue clearValue;
};
const bool hasColor = m_params.colorFormat != VK_FORMAT_UNDEFINED;
const bool hasDepth = m_params.depthFormat != VK_FORMAT_UNDEFINED;
vk::VkRenderingInfoKHR renderingInfo
{
vk::VK_STRUCTURE_TYPE_RENDERING_INFO_KHR,
DE_NULL,
renderingFlags, // VkRenderingFlagsKHR flags;
renderArea, // VkRect2D renderArea;
1u, // deUint32 layerCount;
0u, // deUint32 viewMask;
hasColor, // deUint32 colorAttachmentCount;
(hasColor ? &colorAttachment : DE_NULL), // const VkRenderingAttachmentInfoKHR* pColorAttachments;
(hasDepth ? &depthAttachment : DE_NULL), // const VkRenderingAttachmentInfoKHR* pDepthAttachment;
DE_NULL, // const VkRenderingAttachmentInfoKHR* pStencilAttachment;
};
vk.cmdBeginRendering(cmdBuffer, &renderingInfo);
}
#endif // CTS_USES_VULKANSC
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));
Move<VkCommandBuffer> secCmdBuffer;
const bool hasColor = m_params.colorFormat != VK_FORMAT_UNDEFINED;
const bool hasDepth = m_params.depthFormat != VK_FORMAT_UNDEFINED;
#ifndef CTS_USES_VULKANSC
if (m_params.groupParams->useSecondaryCmdBuffer)
{
secCmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
// record secondary command buffer
if (m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
{
beginSecondaryCmdBuffer(*secCmdBuffer, VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
beginDynamicRender(*secCmdBuffer);
}
else
beginSecondaryCmdBuffer(*secCmdBuffer);
drawCommands(*secCmdBuffer);
if (m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
endRendering(vk, *secCmdBuffer);
endCommandBuffer(vk, *secCmdBuffer);
// record primary command buffer
beginCommandBuffer(vk, *cmdBuffer, 0u);
preRenderCommands(*cmdBuffer);
if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
beginDynamicRender(*cmdBuffer, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
vk.cmdExecuteCommands(*cmdBuffer, 1u, &*secCmdBuffer);
if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
endRendering(vk, *cmdBuffer);
}
else if (m_params.groupParams->useDynamicRendering)
{
beginCommandBuffer(vk, *cmdBuffer);
preRenderCommands(*cmdBuffer);
beginDynamicRender(*cmdBuffer);
drawCommands(*cmdBuffer);
endRendering(vk, *cmdBuffer);
}
#endif // CTS_USES_VULKANSC
if (!m_params.groupParams->useDynamicRendering)
{
beginCommandBuffer(vk, *cmdBuffer);
preRenderCommands(*cmdBuffer);
beginLegacyRender(*cmdBuffer);
drawCommands(*cmdBuffer);
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");
}
if (m_params.groupParams->useDynamicRendering)
context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
}
virtual TestInstance* createInstance (Context& context) const
{
return new MultipleClearsTest(context, m_params);
}
private:
const TestParams m_params;
};
} // anonymous
MultipleClearsWithinRenderPassTests::MultipleClearsWithinRenderPassTests (tcu::TestContext &testCtx, const SharedGroupParams groupParams)
: TestCaseGroup (testCtx, "multiple_clears_within_render_pass", "Tests for multiple clears within render pass")
, m_groupParams (groupParams)
{
}
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)
{
// reduce number of tests for dynamic rendering cases where secondary command buffer is used
if (m_groupParams->useSecondaryCmdBuffer && (topology != Topology::TRIANGLE_STRIP))
continue;
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;
m_groupParams, // SharedGroupParams groupParams;
{ // 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;
m_groupParams, // SharedGroupParams groupParams;
{ // 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;
m_groupParams, // SharedGroupParams groupParams;
{ // 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;
m_groupParams, // SharedGroupParams groupParams;
{ // 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;
m_groupParams, // SharedGroupParams groupParams;
{ // 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;
m_groupParams, // SharedGroupParams groupParams;
{ // 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