blob: efb9d600a908b4da6484972b4adbb9edbe0c61fe [file] [log] [blame]
/*-------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2015 Google 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 RenderPass tests
*//*--------------------------------------------------------------------*/
#include "vktRenderPassTests.hpp"
#include "vktTestCaseUtil.hpp"
#include "vkDefs.hpp"
#include "vkDeviceUtil.hpp"
#include "vkImageUtil.hpp"
#include "vkMemUtil.hpp"
#include "vkPlatform.hpp"
#include "vkPrograms.hpp"
#include "vkQueryUtil.hpp"
#include "vkRef.hpp"
#include "vkRefUtil.hpp"
#include "vkStrUtil.hpp"
#include "vkTypeUtil.hpp"
#include "tcuTestLog.hpp"
#include "tcuResultCollector.hpp"
#include "tcuFormatUtil.hpp"
#include "tcuTextureUtil.hpp"
#include "tcuFloat.hpp"
#include "tcuMaybe.hpp"
#include "tcuVectorUtil.hpp"
#include "deUniquePtr.hpp"
#include "deSharedPtr.hpp"
#include "deStringUtil.hpp"
#include "deSTLUtil.hpp"
#include "deRandom.hpp"
#include <limits>
using namespace vk;
using tcu::Maybe;
using tcu::nothing;
using tcu::just;
using tcu::TestLog;
using tcu::Vec2;
using tcu::IVec2;
using tcu::UVec2;
using tcu::IVec4;
using tcu::UVec4;
using tcu::Vec4;
using tcu::BVec4;
using tcu::ConstPixelBufferAccess;
using tcu::PixelBufferAccess;
using de::UniquePtr;
using std::vector;
using std::string;
namespace vkt
{
namespace
{
enum
{
STENCIL_VALUE = 84u,
// Limit integer values that are representable as floats
MAX_INTEGER_VALUE = ((1u<<22u)-1u)
};
// Utility functions using flattened structs
Move<VkFence> createFence (const DeviceInterface& vk, VkDevice device, VkFenceCreateFlags flags)
{
const VkFenceCreateInfo pCreateInfo =
{
VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
DE_NULL,
flags
};
return createFence(vk, device, &pCreateInfo);
}
Move<VkFramebuffer> createFramebuffer (const DeviceInterface& vk,
VkDevice device,
VkFramebufferCreateFlags pCreateInfo_flags,
VkRenderPass pCreateInfo_renderPass,
deUint32 pCreateInfo_attachmentCount,
const VkImageView* pCreateInfo_pAttachments,
deUint32 pCreateInfo_width,
deUint32 pCreateInfo_height,
deUint32 pCreateInfo_layers)
{
const VkFramebufferCreateInfo pCreateInfo =
{
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
DE_NULL,
pCreateInfo_flags,
pCreateInfo_renderPass,
pCreateInfo_attachmentCount,
pCreateInfo_pAttachments,
pCreateInfo_width,
pCreateInfo_height,
pCreateInfo_layers,
};
return createFramebuffer(vk, device, &pCreateInfo);
}
Move<VkImage> createImage (const DeviceInterface& vk,
VkDevice device,
VkImageCreateFlags pCreateInfo_flags,
VkImageType pCreateInfo_imageType,
VkFormat pCreateInfo_format,
VkExtent3D pCreateInfo_extent,
deUint32 pCreateInfo_mipLevels,
deUint32 pCreateInfo_arrayLayers,
VkSampleCountFlagBits pCreateInfo_samples,
VkImageTiling pCreateInfo_tiling,
VkImageUsageFlags pCreateInfo_usage,
VkSharingMode pCreateInfo_sharingMode,
deUint32 pCreateInfo_queueFamilyCount,
const deUint32* pCreateInfo_pQueueFamilyIndices,
VkImageLayout pCreateInfo_initialLayout)
{
const VkImageCreateInfo pCreateInfo =
{
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
DE_NULL,
pCreateInfo_flags,
pCreateInfo_imageType,
pCreateInfo_format,
pCreateInfo_extent,
pCreateInfo_mipLevels,
pCreateInfo_arrayLayers,
pCreateInfo_samples,
pCreateInfo_tiling,
pCreateInfo_usage,
pCreateInfo_sharingMode,
pCreateInfo_queueFamilyCount,
pCreateInfo_pQueueFamilyIndices,
pCreateInfo_initialLayout
};
return createImage(vk, device, &pCreateInfo);
}
void bindBufferMemory (const DeviceInterface& vk, VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memOffset)
{
VK_CHECK(vk.bindBufferMemory(device, buffer, mem, memOffset));
}
void bindImageMemory (const DeviceInterface& vk, VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memOffset)
{
VK_CHECK(vk.bindImageMemory(device, image, mem, memOffset));
}
Move<VkImageView> createImageView (const DeviceInterface& vk,
VkDevice device,
VkImageViewCreateFlags pCreateInfo_flags,
VkImage pCreateInfo_image,
VkImageViewType pCreateInfo_viewType,
VkFormat pCreateInfo_format,
VkComponentMapping pCreateInfo_components,
VkImageSubresourceRange pCreateInfo_subresourceRange)
{
const VkImageViewCreateInfo pCreateInfo =
{
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
DE_NULL,
pCreateInfo_flags,
pCreateInfo_image,
pCreateInfo_viewType,
pCreateInfo_format,
pCreateInfo_components,
pCreateInfo_subresourceRange,
};
return createImageView(vk, device, &pCreateInfo);
}
Move<VkBuffer> createBuffer (const DeviceInterface& vk,
VkDevice device,
VkBufferCreateFlags pCreateInfo_flags,
VkDeviceSize pCreateInfo_size,
VkBufferUsageFlags pCreateInfo_usage,
VkSharingMode pCreateInfo_sharingMode,
deUint32 pCreateInfo_queueFamilyCount,
const deUint32* pCreateInfo_pQueueFamilyIndices)
{
const VkBufferCreateInfo pCreateInfo =
{
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
DE_NULL,
pCreateInfo_flags,
pCreateInfo_size,
pCreateInfo_usage,
pCreateInfo_sharingMode,
pCreateInfo_queueFamilyCount,
pCreateInfo_pQueueFamilyIndices,
};
return createBuffer(vk, device, &pCreateInfo);
}
Move<VkCommandPool> createCommandPool (const DeviceInterface& vk,
VkDevice device,
VkCommandPoolCreateFlags pCreateInfo_flags,
deUint32 pCreateInfo_queueFamilyIndex)
{
const VkCommandPoolCreateInfo pCreateInfo =
{
VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
DE_NULL,
pCreateInfo_flags,
pCreateInfo_queueFamilyIndex,
};
return createCommandPool(vk, device, &pCreateInfo);
}
void cmdBeginRenderPass (const DeviceInterface& vk,
VkCommandBuffer cmdBuffer,
VkRenderPass pRenderPassBegin_renderPass,
VkFramebuffer pRenderPassBegin_framebuffer,
VkRect2D pRenderPassBegin_renderArea,
deUint32 pRenderPassBegin_clearValueCount,
const VkClearValue* pRenderPassBegin_pAttachmentClearValues,
VkSubpassContents contents)
{
const VkRenderPassBeginInfo pRenderPassBegin =
{
VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
DE_NULL,
pRenderPassBegin_renderPass,
pRenderPassBegin_framebuffer,
pRenderPassBegin_renderArea,
pRenderPassBegin_clearValueCount,
pRenderPassBegin_pAttachmentClearValues,
};
vk.cmdBeginRenderPass(cmdBuffer, &pRenderPassBegin, contents);
}
Move<VkCommandBuffer> allocateCommandBuffer (const DeviceInterface& vk,
VkDevice device,
VkCommandPool pCreateInfo_commandPool,
VkCommandBufferLevel pCreateInfo_level)
{
const VkCommandBufferAllocateInfo pAllocateInfo =
{
VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
DE_NULL,
pCreateInfo_commandPool,
pCreateInfo_level,
1u, // bufferCount
};
return allocateCommandBuffer(vk, device, &pAllocateInfo);
}
void beginCommandBuffer (const DeviceInterface& vk,
VkCommandBuffer cmdBuffer,
VkCommandBufferUsageFlags pBeginInfo_flags,
VkRenderPass pInheritanceInfo_renderPass,
deUint32 pInheritanceInfo_subpass,
VkFramebuffer pInheritanceInfo_framebuffer,
VkBool32 pInheritanceInfo_occlusionQueryEnable,
VkQueryControlFlags pInheritanceInfo_queryFlags,
VkQueryPipelineStatisticFlags pInheritanceInfo_pipelineStatistics)
{
const VkCommandBufferInheritanceInfo pInheritanceInfo =
{
VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
DE_NULL,
pInheritanceInfo_renderPass,
pInheritanceInfo_subpass,
pInheritanceInfo_framebuffer,
pInheritanceInfo_occlusionQueryEnable,
pInheritanceInfo_queryFlags,
pInheritanceInfo_pipelineStatistics,
};
const VkCommandBufferBeginInfo pBeginInfo =
{
VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
DE_NULL,
pBeginInfo_flags,
&pInheritanceInfo,
};
VK_CHECK(vk.beginCommandBuffer(cmdBuffer, &pBeginInfo));
}
void endCommandBuffer (const DeviceInterface& vk, VkCommandBuffer cmdBuffer)
{
VK_CHECK(vk.endCommandBuffer(cmdBuffer));
}
void queueSubmit (const DeviceInterface& vk, VkQueue queue, deUint32 cmdBufferCount, const VkCommandBuffer* pCmdBuffers, VkFence fence)
{
const VkSubmitInfo submitInfo =
{
VK_STRUCTURE_TYPE_SUBMIT_INFO,
DE_NULL,
0u, // waitSemaphoreCount
(const VkSemaphore*)DE_NULL, // pWaitSemaphores
(const VkPipelineStageFlags*)DE_NULL,
cmdBufferCount, // commandBufferCount
pCmdBuffers,
0u, // signalSemaphoreCount
(const VkSemaphore*)DE_NULL, // pSignalSemaphores
};
VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfo, fence));
}
void waitForFences (const DeviceInterface& vk, VkDevice device, deUint32 fenceCount, const VkFence* pFences, VkBool32 waitAll, deUint64 timeout)
{
VK_CHECK(vk.waitForFences(device, fenceCount, pFences, waitAll, timeout));
}
VkImageAspectFlags getImageAspectFlags (VkFormat vkFormat)
{
const tcu::TextureFormat format = mapVkFormat(vkFormat);
DE_STATIC_ASSERT(tcu::TextureFormat::CHANNELORDER_LAST == 21);
switch (format.order)
{
case tcu::TextureFormat::DS:
return VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_DEPTH_BIT;
case tcu::TextureFormat::D:
return VK_IMAGE_ASPECT_DEPTH_BIT;
case tcu::TextureFormat::S:
return VK_IMAGE_ASPECT_STENCIL_BIT;
default:
return VK_IMAGE_ASPECT_COLOR_BIT;
}
}
VkAccessFlags getAllMemoryReadFlags (void)
{
return VK_ACCESS_TRANSFER_READ_BIT
| VK_ACCESS_UNIFORM_READ_BIT
| VK_ACCESS_HOST_READ_BIT
| VK_ACCESS_INDEX_READ_BIT
| VK_ACCESS_SHADER_READ_BIT
| VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT
| VK_ACCESS_INDIRECT_COMMAND_READ_BIT
| VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
| VK_ACCESS_INPUT_ATTACHMENT_READ_BIT
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
}
VkAccessFlags getAllMemoryWriteFlags (void)
{
return VK_ACCESS_TRANSFER_WRITE_BIT
| VK_ACCESS_HOST_WRITE_BIT
| VK_ACCESS_SHADER_WRITE_BIT
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
}
VkAccessFlags getMemoryFlagsForLayout (const VkImageLayout layout)
{
switch (layout)
{
case VK_IMAGE_LAYOUT_GENERAL: return getAllMemoryReadFlags() | getAllMemoryWriteFlags();
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: return VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: return VK_ACCESS_SHADER_READ_BIT;
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: return VK_ACCESS_TRANSFER_READ_BIT;
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: return VK_ACCESS_TRANSFER_WRITE_BIT;
default:
return (VkAccessFlags)0;
}
}
VkPipelineStageFlags getAllPipelineStageFlags (void)
{
return VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT
| VK_PIPELINE_STAGE_TRANSFER_BIT
| VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT
| VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
| VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT
| VK_PIPELINE_STAGE_VERTEX_INPUT_BIT
| VK_PIPELINE_STAGE_VERTEX_SHADER_BIT
| VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
| VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT
| VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT
| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
| VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
}
class AttachmentReference
{
public:
AttachmentReference (deUint32 attachment,
VkImageLayout layout)
: m_attachment (attachment)
, m_layout (layout)
{
}
deUint32 getAttachment (void) const { return m_attachment; }
VkImageLayout getImageLayout (void) const { return m_layout; }
private:
deUint32 m_attachment;
VkImageLayout m_layout;
};
class Subpass
{
public:
Subpass (VkPipelineBindPoint pipelineBindPoint,
VkSubpassDescriptionFlags flags,
const vector<AttachmentReference>& inputAttachments,
const vector<AttachmentReference>& colorAttachments,
const vector<AttachmentReference>& resolveAttachments,
AttachmentReference depthStencilAttachment,
const vector<AttachmentReference>& preserveAttachments)
: m_pipelineBindPoint (pipelineBindPoint)
, m_flags (flags)
, m_inputAttachments (inputAttachments)
, m_colorAttachments (colorAttachments)
, m_resolveAttachments (resolveAttachments)
, m_depthStencilAttachment (depthStencilAttachment)
, m_preserveAttachments (preserveAttachments)
{
}
VkPipelineBindPoint getPipelineBindPoint (void) const { return m_pipelineBindPoint; }
VkSubpassDescriptionFlags getFlags (void) const { return m_flags; }
const vector<AttachmentReference>& getInputAttachments (void) const { return m_inputAttachments; }
const vector<AttachmentReference>& getColorAttachments (void) const { return m_colorAttachments; }
const vector<AttachmentReference>& getResolveAttachments (void) const { return m_resolveAttachments; }
const AttachmentReference& getDepthStencilAttachment (void) const { return m_depthStencilAttachment; }
const vector<AttachmentReference>& getPreserveAttachments (void) const { return m_preserveAttachments; }
private:
VkPipelineBindPoint m_pipelineBindPoint;
VkSubpassDescriptionFlags m_flags;
vector<AttachmentReference> m_inputAttachments;
vector<AttachmentReference> m_colorAttachments;
vector<AttachmentReference> m_resolveAttachments;
AttachmentReference m_depthStencilAttachment;
vector<AttachmentReference> m_preserveAttachments;
};
class SubpassDependency
{
public:
SubpassDependency (deUint32 srcPass,
deUint32 dstPass,
VkPipelineStageFlags srcStageMask,
VkPipelineStageFlags dstStageMask,
VkAccessFlags outputMask,
VkAccessFlags inputMask,
VkDependencyFlags flags)
: m_srcPass (srcPass)
, m_dstPass (dstPass)
, m_srcStageMask (srcStageMask)
, m_dstStageMask (dstStageMask)
, m_outputMask (outputMask)
, m_inputMask (inputMask)
, m_flags (flags)
{
}
deUint32 getSrcPass (void) const { return m_srcPass; }
deUint32 getDstPass (void) const { return m_dstPass; }
VkPipelineStageFlags getSrcStageMask (void) const { return m_srcStageMask; }
VkPipelineStageFlags getDstStageMask (void) const { return m_dstStageMask; }
VkAccessFlags getOutputMask (void) const { return m_outputMask; }
VkAccessFlags getInputMask (void) const { return m_inputMask; }
VkDependencyFlags getFlags (void) const { return m_flags; }
private:
deUint32 m_srcPass;
deUint32 m_dstPass;
VkPipelineStageFlags m_srcStageMask;
VkPipelineStageFlags m_dstStageMask;
VkAccessFlags m_outputMask;
VkAccessFlags m_inputMask;
VkDependencyFlags m_flags;
};
class Attachment
{
public:
Attachment (VkFormat format,
VkSampleCountFlagBits samples,
VkAttachmentLoadOp loadOp,
VkAttachmentStoreOp storeOp,
VkAttachmentLoadOp stencilLoadOp,
VkAttachmentStoreOp stencilStoreOp,
VkImageLayout initialLayout,
VkImageLayout finalLayout)
: m_format (format)
, m_samples (samples)
, m_loadOp (loadOp)
, m_storeOp (storeOp)
, m_stencilLoadOp (stencilLoadOp)
, m_stencilStoreOp (stencilStoreOp)
, m_initialLayout (initialLayout)
, m_finalLayout (finalLayout)
{
}
VkFormat getFormat (void) const { return m_format; }
VkSampleCountFlagBits getSamples (void) const { return m_samples; }
VkAttachmentLoadOp getLoadOp (void) const { return m_loadOp; }
VkAttachmentStoreOp getStoreOp (void) const { return m_storeOp; }
VkAttachmentLoadOp getStencilLoadOp (void) const { return m_stencilLoadOp; }
VkAttachmentStoreOp getStencilStoreOp (void) const { return m_stencilStoreOp; }
VkImageLayout getInitialLayout (void) const { return m_initialLayout; }
VkImageLayout getFinalLayout (void) const { return m_finalLayout; }
private:
VkFormat m_format;
VkSampleCountFlagBits m_samples;
VkAttachmentLoadOp m_loadOp;
VkAttachmentStoreOp m_storeOp;
VkAttachmentLoadOp m_stencilLoadOp;
VkAttachmentStoreOp m_stencilStoreOp;
VkImageLayout m_initialLayout;
VkImageLayout m_finalLayout;
};
class RenderPass
{
public:
RenderPass (const vector<Attachment>& attachments,
const vector<Subpass>& subpasses,
const vector<SubpassDependency>& dependencies)
: m_attachments (attachments)
, m_subpasses (subpasses)
, m_dependencies (dependencies)
{
}
const vector<Attachment>& getAttachments (void) const { return m_attachments; }
const vector<Subpass>& getSubpasses (void) const { return m_subpasses; }
const vector<SubpassDependency>& getDependencies (void) const { return m_dependencies; }
private:
const vector<Attachment> m_attachments;
const vector<Subpass> m_subpasses;
const vector<SubpassDependency> m_dependencies;
};
struct TestConfig
{
enum RenderTypes
{
RENDERTYPES_NONE = 0,
RENDERTYPES_CLEAR = (1<<1),
RENDERTYPES_DRAW = (1<<2)
};
enum CommandBufferTypes
{
COMMANDBUFFERTYPES_INLINE = (1<<0),
COMMANDBUFFERTYPES_SECONDARY = (1<<1)
};
enum ImageMemory
{
IMAGEMEMORY_STRICT = (1<<0),
IMAGEMEMORY_LAZY = (1<<1)
};
TestConfig (const RenderPass& renderPass_,
RenderTypes renderTypes_,
CommandBufferTypes commandBufferTypes_,
ImageMemory imageMemory_,
const UVec2& targetSize_,
const UVec2& renderPos_,
const UVec2& renderSize_,
deUint32 seed_)
: renderPass (renderPass_)
, renderTypes (renderTypes_)
, commandBufferTypes (commandBufferTypes_)
, imageMemory (imageMemory_)
, targetSize (targetSize_)
, renderPos (renderPos_)
, renderSize (renderSize_)
, seed (seed_)
{
}
RenderPass renderPass;
RenderTypes renderTypes;
CommandBufferTypes commandBufferTypes;
ImageMemory imageMemory;
UVec2 targetSize;
UVec2 renderPos;
UVec2 renderSize;
deUint32 seed;
};
TestConfig::RenderTypes operator| (TestConfig::RenderTypes a, TestConfig::RenderTypes b)
{
return (TestConfig::RenderTypes)(((deUint32)a) | ((deUint32)b));
}
TestConfig::CommandBufferTypes operator| (TestConfig::CommandBufferTypes a, TestConfig::CommandBufferTypes b)
{
return (TestConfig::CommandBufferTypes)(((deUint32)a) | ((deUint32)b));
}
TestConfig::ImageMemory operator| (TestConfig::ImageMemory a, TestConfig::ImageMemory b)
{
return (TestConfig::ImageMemory)(((deUint32)a) | ((deUint32)b));
}
void logRenderPassInfo (TestLog& log,
const RenderPass& renderPass)
{
const tcu::ScopedLogSection section (log, "RenderPass", "RenderPass");
{
const tcu::ScopedLogSection attachmentsSection (log, "Attachments", "Attachments");
const vector<Attachment>& attachments = renderPass.getAttachments();
for (size_t attachmentNdx = 0; attachmentNdx < attachments.size(); attachmentNdx++)
{
const tcu::ScopedLogSection attachmentSection (log, "Attachment" + de::toString(attachmentNdx), "Attachment " + de::toString(attachmentNdx));
const Attachment& attachment = attachments[attachmentNdx];
log << TestLog::Message << "Format: " << attachment.getFormat() << TestLog::EndMessage;
log << TestLog::Message << "Samples: " << attachment.getSamples() << TestLog::EndMessage;
log << TestLog::Message << "LoadOp: " << attachment.getLoadOp() << TestLog::EndMessage;
log << TestLog::Message << "StoreOp: " << attachment.getStoreOp() << TestLog::EndMessage;
log << TestLog::Message << "StencilLoadOp: " << attachment.getStencilLoadOp() << TestLog::EndMessage;
log << TestLog::Message << "StencilStoreOp: " << attachment.getStencilStoreOp() << TestLog::EndMessage;
log << TestLog::Message << "InitialLayout: " << attachment.getInitialLayout() << TestLog::EndMessage;
log << TestLog::Message << "FinalLayout: " << attachment.getFinalLayout() << TestLog::EndMessage;
}
}
{
const tcu::ScopedLogSection subpassesSection (log, "Subpasses", "Subpasses");
const vector<Subpass>& subpasses = renderPass.getSubpasses();
for (size_t subpassNdx = 0; subpassNdx < subpasses.size(); subpassNdx++)
{
const tcu::ScopedLogSection subpassSection (log, "Subpass" + de::toString(subpassNdx), "Subpass " + de::toString(subpassNdx));
const Subpass& subpass = subpasses[subpassNdx];
const vector<AttachmentReference>& inputAttachments = subpass.getInputAttachments();
const vector<AttachmentReference>& colorAttachments = subpass.getColorAttachments();
const vector<AttachmentReference>& resolveAttachments = subpass.getResolveAttachments();
const vector<AttachmentReference>& preserveAttachments = subpass.getPreserveAttachments();
if (!inputAttachments.empty())
{
const tcu::ScopedLogSection inputAttachmentsSection (log, "Inputs", "Inputs");
for (size_t inputNdx = 0; inputNdx < inputAttachments.size(); inputNdx++)
{
const tcu::ScopedLogSection inputAttachmentSection (log, "Input" + de::toString(inputNdx), "Input " + de::toString(inputNdx));
const AttachmentReference& inputAttachment = inputAttachments[inputNdx];
log << TestLog::Message << "Attachment: " << inputAttachment.getAttachment() << TestLog::EndMessage;
log << TestLog::Message << "Layout: " << inputAttachment.getImageLayout() << TestLog::EndMessage;
}
}
if (subpass.getDepthStencilAttachment().getAttachment() != VK_ATTACHMENT_UNUSED)
{
const tcu::ScopedLogSection depthStencilAttachmentSection (log, "DepthStencil", "DepthStencil");
const AttachmentReference& depthStencilAttachment = subpass.getDepthStencilAttachment();
log << TestLog::Message << "Attachment: " << depthStencilAttachment.getAttachment() << TestLog::EndMessage;
log << TestLog::Message << "Layout: " << depthStencilAttachment.getImageLayout() << TestLog::EndMessage;
}
if (!colorAttachments.empty())
{
const tcu::ScopedLogSection colorAttachmentsSection (log, "Colors", "Colors");
for (size_t colorNdx = 0; colorNdx < colorAttachments.size(); colorNdx++)
{
const tcu::ScopedLogSection colorAttachmentSection (log, "Color" + de::toString(colorNdx), "Color " + de::toString(colorNdx));
const AttachmentReference& colorAttachment = colorAttachments[colorNdx];
log << TestLog::Message << "Attachment: " << colorAttachment.getAttachment() << TestLog::EndMessage;
log << TestLog::Message << "Layout: " << colorAttachment.getImageLayout() << TestLog::EndMessage;
}
}
if (!resolveAttachments.empty())
{
const tcu::ScopedLogSection resolveAttachmentsSection (log, "Resolves", "Resolves");
for (size_t resolveNdx = 0; resolveNdx < resolveAttachments.size(); resolveNdx++)
{
const tcu::ScopedLogSection resolveAttachmentSection (log, "Resolve" + de::toString(resolveNdx), "Resolve " + de::toString(resolveNdx));
const AttachmentReference& resolveAttachment = resolveAttachments[resolveNdx];
log << TestLog::Message << "Attachment: " << resolveAttachment.getAttachment() << TestLog::EndMessage;
log << TestLog::Message << "Layout: " << resolveAttachment.getImageLayout() << TestLog::EndMessage;
}
}
if (!preserveAttachments.empty())
{
const tcu::ScopedLogSection preserveAttachmentsSection (log, "Preserves", "Preserves");
for (size_t preserveNdx = 0; preserveNdx < preserveAttachments.size(); preserveNdx++)
{
const tcu::ScopedLogSection preserveAttachmentSection (log, "Preserve" + de::toString(preserveNdx), "Preserve " + de::toString(preserveNdx));
const AttachmentReference& preserveAttachment = preserveAttachments[preserveNdx];
log << TestLog::Message << "Attachment: " << preserveAttachment.getAttachment() << TestLog::EndMessage;
log << TestLog::Message << "Layout: " << preserveAttachment.getImageLayout() << TestLog::EndMessage;
}
}
}
}
if (!renderPass.getDependencies().empty())
{
const tcu::ScopedLogSection dependenciesSection (log, "Dependencies", "Dependencies");
for (size_t depNdx = 0; depNdx < renderPass.getDependencies().size(); depNdx++)
{
const tcu::ScopedLogSection dependencySection (log, "Dependency" + de::toString(depNdx), "Dependency " + de::toString(depNdx));
const SubpassDependency& dep = renderPass.getDependencies()[depNdx];
log << TestLog::Message << "Source: " << dep.getSrcPass() << TestLog::EndMessage;
log << TestLog::Message << "Destination: " << dep.getDstPass() << TestLog::EndMessage;
log << TestLog::Message << "Source Stage Mask: " << dep.getSrcStageMask() << TestLog::EndMessage;
log << TestLog::Message << "Destination Stage Mask: " << dep.getDstStageMask() << TestLog::EndMessage;
log << TestLog::Message << "Input Mask: " << dep.getInputMask() << TestLog::EndMessage;
log << TestLog::Message << "Output Mask: " << dep.getOutputMask() << TestLog::EndMessage;
log << TestLog::Message << "Dependency Flags: " << getDependencyFlagsStr(dep.getFlags()) << TestLog::EndMessage;
}
}
}
std::string clearColorToString (VkFormat vkFormat, VkClearColorValue value)
{
const tcu::TextureFormat format = mapVkFormat(vkFormat);
const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(format.type);
const tcu::BVec4 channelMask = tcu::getTextureFormatChannelMask(format);
std::ostringstream stream;
stream << "(";
switch (channelClass)
{
case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
for (int i = 0; i < 4; i++)
{
if (i > 0)
stream << ", ";
if (channelMask[i])
stream << value.int32[i];
else
stream << "Undef";
}
break;
case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
for (int i = 0; i < 4; i++)
{
if (i > 0)
stream << ", ";
if (channelMask[i])
stream << value.uint32[i];
else
stream << "Undef";
}
break;
case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
for (int i = 0; i < 4; i++)
{
if (i > 0)
stream << ", ";
if (channelMask[i])
stream << value.float32[i];
else
stream << "Undef";
}
break;
default:
DE_FATAL("Unknown channel class");
}
stream << ")";
return stream.str();
}
std::string clearValueToString (VkFormat vkFormat, VkClearValue value)
{
const tcu::TextureFormat format = mapVkFormat(vkFormat);
if (tcu::hasStencilComponent(format.order) || tcu::hasDepthComponent(format.order))
{
std::ostringstream stream;
stream << "(";
if (tcu::hasStencilComponent(format.order))
stream << "stencil: " << value.depthStencil.stencil;
if (tcu::hasStencilComponent(format.order) && tcu::hasDepthComponent(format.order))
stream << ", ";
if (tcu::hasDepthComponent(format.order))
stream << "depth: " << value.depthStencil.depth;
stream << ")";
return stream.str();
}
else
return clearColorToString(vkFormat, value.color);
}
VkClearColorValue randomColorClearValue (const Attachment& attachment, de::Random& rng)
{
const float clearNan = tcu::Float32::nan().asFloat();
const tcu::TextureFormat format = mapVkFormat(attachment.getFormat());
const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(format.type);
const tcu::BVec4 channelMask = tcu::getTextureFormatChannelMask(format);
VkClearColorValue clearColor;
switch (channelClass)
{
case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
{
const tcu::IVec4 valueMin = tcu::getFormatMinIntValue(format);
const tcu::IVec4 valueMax = tcu::getFormatMaxIntValue(format);
for (int ndx = 0; ndx < 4; ndx++)
{
if (!channelMask[ndx])
clearColor.int32[ndx] = std::numeric_limits<deInt32>::min();
else
clearColor.uint32[ndx] = rng.getInt(valueMin[ndx], valueMax[ndx]);
}
break;
}
case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
{
const UVec4 valueMax = tcu::getFormatMaxUintValue(format);
for (int ndx = 0; ndx < 4; ndx++)
{
if (!channelMask[ndx])
clearColor.uint32[ndx] = std::numeric_limits<deUint32>::max();
else
clearColor.uint32[ndx] = rng.getUint32() % valueMax[ndx];
}
break;
}
case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
{
const tcu::TextureFormatInfo formatInfo = tcu::getTextureFormatInfo(format);
for (int ndx = 0; ndx < 4; ndx++)
{
if (!channelMask[ndx])
clearColor.float32[ndx] = clearNan;
else
clearColor.float32[ndx] = formatInfo.valueMin[ndx] + rng.getFloat() * (formatInfo.valueMax[ndx] - formatInfo.valueMin[ndx]);
}
break;
}
default:
DE_FATAL("Unknown channel class");
}
return clearColor;
}
VkAttachmentDescription createAttachmentDescription (const Attachment& attachment)
{
const VkAttachmentDescription attachmentDescription =
{
0, // flags
attachment.getFormat(), // format
attachment.getSamples(), // samples
attachment.getLoadOp(), // loadOp
attachment.getStoreOp(), // storeOp
attachment.getStencilLoadOp(), // stencilLoadOp
attachment.getStencilStoreOp(), // stencilStoreOp
attachment.getInitialLayout(), // initialLayout
attachment.getFinalLayout(), // finalLayout
};
return attachmentDescription;
}
VkAttachmentReference createAttachmentReference (const AttachmentReference& referenceInfo)
{
const VkAttachmentReference reference =
{
referenceInfo.getAttachment(), // attachment;
referenceInfo.getImageLayout() // layout;
};
return reference;
}
VkSubpassDescription createSubpassDescription (const Subpass& subpass,
vector<VkAttachmentReference>* attachmentReferenceLists,
vector<deUint32>* preserveAttachmentReferences)
{
vector<VkAttachmentReference>& inputAttachmentReferences = attachmentReferenceLists[0];
vector<VkAttachmentReference>& colorAttachmentReferences = attachmentReferenceLists[1];
vector<VkAttachmentReference>& resolveAttachmentReferences = attachmentReferenceLists[2];
vector<VkAttachmentReference>& depthStencilAttachmentReferences = attachmentReferenceLists[3];
for (size_t attachmentNdx = 0; attachmentNdx < subpass.getColorAttachments().size(); attachmentNdx++)
colorAttachmentReferences.push_back(createAttachmentReference(subpass.getColorAttachments()[attachmentNdx]));
for (size_t attachmentNdx = 0; attachmentNdx < subpass.getInputAttachments().size(); attachmentNdx++)
inputAttachmentReferences.push_back(createAttachmentReference(subpass.getInputAttachments()[attachmentNdx]));
for (size_t attachmentNdx = 0; attachmentNdx < subpass.getResolveAttachments().size(); attachmentNdx++)
resolveAttachmentReferences.push_back(createAttachmentReference(subpass.getResolveAttachments()[attachmentNdx]));
depthStencilAttachmentReferences.push_back(createAttachmentReference(subpass.getDepthStencilAttachment()));
for (size_t attachmentNdx = 0; attachmentNdx < subpass.getPreserveAttachments().size(); attachmentNdx++)
preserveAttachmentReferences->push_back(subpass.getPreserveAttachments()[attachmentNdx].getAttachment());
DE_ASSERT(resolveAttachmentReferences.empty() || colorAttachmentReferences.size() == resolveAttachmentReferences.size());
{
const VkSubpassDescription subpassDescription =
{
subpass.getFlags(), // flags;
subpass.getPipelineBindPoint(), // pipelineBindPoint;
(deUint32)inputAttachmentReferences.size(), // inputCount;
inputAttachmentReferences.empty() ? DE_NULL : &inputAttachmentReferences[0], // inputAttachments;
(deUint32)colorAttachmentReferences.size(), // colorCount;
colorAttachmentReferences.empty() ? DE_NULL : &colorAttachmentReferences[0], // colorAttachments;
resolveAttachmentReferences.empty() ? DE_NULL : &resolveAttachmentReferences[0], // resolveAttachments;
&depthStencilAttachmentReferences[0], // pDepthStencilAttachment;
(deUint32)preserveAttachmentReferences->size(), // preserveCount;
preserveAttachmentReferences->empty() ? DE_NULL : &(*preserveAttachmentReferences)[0] // preserveAttachments;
};
return subpassDescription;
}
}
VkSubpassDependency createSubpassDependency (const SubpassDependency& dependencyInfo)
{
const VkSubpassDependency dependency =
{
dependencyInfo.getSrcPass(), // srcSubpass;
dependencyInfo.getDstPass(), // destSubpass;
dependencyInfo.getSrcStageMask(), // srcStageMask;
dependencyInfo.getDstStageMask(), // destStageMask;
dependencyInfo.getOutputMask(), // outputMask;
dependencyInfo.getInputMask(), // inputMask;
dependencyInfo.getFlags() // dependencyFlags;
};
return dependency;
}
Move<VkRenderPass> createRenderPass (const DeviceInterface& vk,
VkDevice device,
const RenderPass& renderPassInfo)
{
const size_t perSubpassAttachmentReferenceLists = 4;
vector<VkAttachmentDescription> attachments;
vector<VkSubpassDescription> subpasses;
vector<VkSubpassDependency> dependencies;
vector<vector<VkAttachmentReference> > attachmentReferenceLists(renderPassInfo.getSubpasses().size() * perSubpassAttachmentReferenceLists);
vector<vector<deUint32> > preserveAttachments(renderPassInfo.getSubpasses().size());
for (size_t attachmentNdx = 0; attachmentNdx < renderPassInfo.getAttachments().size(); attachmentNdx++)
attachments.push_back(createAttachmentDescription(renderPassInfo.getAttachments()[attachmentNdx]));
for (size_t subpassNdx = 0; subpassNdx < renderPassInfo.getSubpasses().size(); subpassNdx++)
subpasses.push_back(createSubpassDescription(renderPassInfo.getSubpasses()[subpassNdx], &(attachmentReferenceLists[subpassNdx * perSubpassAttachmentReferenceLists]), &preserveAttachments[subpassNdx]));
for (size_t depNdx = 0; depNdx < renderPassInfo.getDependencies().size(); depNdx++)
dependencies.push_back(createSubpassDependency(renderPassInfo.getDependencies()[depNdx]));
{
const VkRenderPassCreateInfo createInfo =
{
VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
DE_NULL,
(VkRenderPassCreateFlags)0u,
(deUint32)attachments.size(),
(attachments.empty() ? DE_NULL : &attachments[0]),
(deUint32)subpasses.size(),
(subpasses.empty() ? DE_NULL : &subpasses[0]),
(deUint32)dependencies.size(),
(dependencies.empty() ? DE_NULL : &dependencies[0])
};
return createRenderPass(vk, device, &createInfo);
}
}
Move<VkFramebuffer> createFramebuffer (const DeviceInterface& vk,
VkDevice device,
VkRenderPass renderPass,
const UVec2& size,
const vector<VkImageView>& attachments)
{
return createFramebuffer(vk, device, 0u, renderPass, (deUint32)attachments.size(), attachments.empty() ? DE_NULL : &attachments[0], size.x(), size.y(), 1u);
}
Move<VkImage> createAttachmentImage (const DeviceInterface& vk,
VkDevice device,
deUint32 queueIndex,
const UVec2& size,
VkFormat format,
VkSampleCountFlagBits samples,
VkImageUsageFlags usageFlags,
VkImageLayout layout)
{
const VkExtent3D size_ = { size.x(), size.y(), 1u };
VkImageUsageFlags targetUsageFlags = 0;
const tcu::TextureFormat textureFormat = mapVkFormat(format);
if (tcu::hasDepthComponent(textureFormat.order) || tcu::hasStencilComponent(textureFormat.order))
{
targetUsageFlags |= vk::VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
}
else
{
targetUsageFlags |= vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
}
return createImage(vk, device,
(VkImageCreateFlags)0,
VK_IMAGE_TYPE_2D,
format,
size_,
1u /* mipLevels */,
1u /* arraySize */,
samples,
VK_IMAGE_TILING_OPTIMAL,
usageFlags | targetUsageFlags,
VK_SHARING_MODE_EXCLUSIVE,
1,
&queueIndex,
layout);
}
de::MovePtr<Allocation> createImageMemory (const DeviceInterface& vk,
VkDevice device,
Allocator& allocator,
VkImage image,
bool lazy)
{
de::MovePtr<Allocation> allocation (allocator.allocate(getImageMemoryRequirements(vk, device, image), lazy ? MemoryRequirement::LazilyAllocated : MemoryRequirement::Any));
bindImageMemory(vk, device, image, allocation->getMemory(), allocation->getOffset());
return allocation;
}
Move<VkImageView> createImageAttachmentView (const DeviceInterface& vk,
VkDevice device,
VkImage image,
VkFormat format,
VkImageAspectFlags aspect)
{
const VkImageSubresourceRange range =
{
aspect,
0,
1,
0,
1
};
return createImageView(vk, device, 0u, image, VK_IMAGE_VIEW_TYPE_2D, format, makeComponentMappingRGBA(), range);
}
VkClearValue randomClearValue (const Attachment& attachment, de::Random& rng)
{
const float clearNan = tcu::Float32::nan().asFloat();
const tcu::TextureFormat format = mapVkFormat(attachment.getFormat());
if (tcu::hasStencilComponent(format.order) || tcu::hasDepthComponent(format.order))
{
VkClearValue clearValue;
clearValue.depthStencil.depth = clearNan;
clearValue.depthStencil.stencil = 255;
if (tcu::hasStencilComponent(format.order))
clearValue.depthStencil.stencil = rng.getInt(0, 255);
if (tcu::hasDepthComponent(format.order))
clearValue.depthStencil.depth = rng.getFloat();
return clearValue;
}
else
{
VkClearValue clearValue;
clearValue.color = randomColorClearValue(attachment, rng);
return clearValue;
}
}
class AttachmentResources
{
public:
AttachmentResources (const DeviceInterface& vk,
VkDevice device,
Allocator& allocator,
deUint32 queueIndex,
const UVec2& size,
const Attachment& attachmentInfo,
VkImageUsageFlags usageFlags)
: m_image (createAttachmentImage(vk, device, queueIndex, size, attachmentInfo.getFormat(), attachmentInfo.getSamples(), usageFlags, VK_IMAGE_LAYOUT_UNDEFINED))
, m_imageMemory (createImageMemory(vk, device, allocator, *m_image, ((usageFlags & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) != 0)))
, m_attachmentView (createImageAttachmentView(vk, device, *m_image, attachmentInfo.getFormat(), getImageAspectFlags(attachmentInfo.getFormat())))
{
if ((usageFlags & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) == 0)
{
const tcu::TextureFormat format = mapVkFormat(attachmentInfo.getFormat());
if (tcu::hasDepthComponent(format.order) && tcu::hasStencilComponent(format.order))
{
const tcu::TextureFormat depthFormat = getDepthCopyFormat(attachmentInfo.getFormat());
const tcu::TextureFormat stencilFormat = getStencilCopyFormat(attachmentInfo.getFormat());
m_bufferSize = size.x() * size.y() * depthFormat.getPixelSize();
m_secondaryBufferSize = size.x() * size.y() * stencilFormat.getPixelSize();
m_buffer = createBuffer(vk, device, 0, m_bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_SHARING_MODE_EXCLUSIVE, 1, &queueIndex);
m_bufferMemory = allocator.allocate(getBufferMemoryRequirements(vk, device, *m_buffer), MemoryRequirement::HostVisible);
bindBufferMemory(vk, device, *m_buffer, m_bufferMemory->getMemory(), m_bufferMemory->getOffset());
m_secondaryBuffer = createBuffer(vk, device, 0, m_secondaryBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_SHARING_MODE_EXCLUSIVE, 1, &queueIndex);
m_secondaryBufferMemory = allocator.allocate(getBufferMemoryRequirements(vk, device, *m_secondaryBuffer), MemoryRequirement::HostVisible);
bindBufferMemory(vk, device, *m_secondaryBuffer, m_secondaryBufferMemory->getMemory(), m_secondaryBufferMemory->getOffset());
}
else
{
m_bufferSize = size.x() * size.y() * format.getPixelSize();
m_buffer = createBuffer(vk, device, 0, m_bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_SHARING_MODE_EXCLUSIVE, 1, &queueIndex);
m_bufferMemory = allocator.allocate(getBufferMemoryRequirements(vk, device, *m_buffer), MemoryRequirement::HostVisible);
bindBufferMemory(vk, device, *m_buffer, m_bufferMemory->getMemory(), m_bufferMemory->getOffset());
}
}
}
~AttachmentResources (void)
{
}
VkImageView getAttachmentView (void) const
{
return *m_attachmentView;
}
VkImage getImage (void) const
{
return *m_image;
}
VkBuffer getBuffer (void) const
{
DE_ASSERT(*m_buffer != DE_NULL);
return *m_buffer;
}
VkDeviceSize getBufferSize (void) const
{
DE_ASSERT(*m_buffer != DE_NULL);
return m_bufferSize;
}
const Allocation& getResultMemory (void) const
{
DE_ASSERT(m_bufferMemory);
return *m_bufferMemory;
}
VkBuffer getSecondaryBuffer (void) const
{
DE_ASSERT(*m_secondaryBuffer != DE_NULL);
return *m_secondaryBuffer;
}
VkDeviceSize getSecondaryBufferSize (void) const
{
DE_ASSERT(*m_secondaryBuffer != DE_NULL);
return m_secondaryBufferSize;
}
const Allocation& getSecondaryResultMemory (void) const
{
DE_ASSERT(m_secondaryBufferMemory);
return *m_secondaryBufferMemory;
}
private:
const Unique<VkImage> m_image;
const UniquePtr<Allocation> m_imageMemory;
const Unique<VkImageView> m_attachmentView;
Move<VkBuffer> m_buffer;
VkDeviceSize m_bufferSize;
de::MovePtr<Allocation> m_bufferMemory;
Move<VkBuffer> m_secondaryBuffer;
VkDeviceSize m_secondaryBufferSize;
de::MovePtr<Allocation> m_secondaryBufferMemory;
};
void uploadBufferData (const DeviceInterface& vk,
VkDevice device,
const Allocation& memory,
size_t size,
const void* data)
{
const VkMappedMemoryRange range =
{
VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, // sType;
DE_NULL, // pNext;
memory.getMemory(), // mem;
memory.getOffset(), // offset;
(VkDeviceSize)size // size;
};
void* const ptr = memory.getHostPtr();
deMemcpy(ptr, data, size);
VK_CHECK(vk.flushMappedMemoryRanges(device, 1, &range));
}
VkImageAspectFlagBits getPrimaryImageAspect (tcu::TextureFormat::ChannelOrder order)
{
DE_STATIC_ASSERT(tcu::TextureFormat::CHANNELORDER_LAST == 21);
switch (order)
{
case tcu::TextureFormat::D:
case tcu::TextureFormat::DS:
return VK_IMAGE_ASPECT_DEPTH_BIT;
case tcu::TextureFormat::S:
return VK_IMAGE_ASPECT_STENCIL_BIT;
default:
return VK_IMAGE_ASPECT_COLOR_BIT;
}
}
class RenderQuad
{
public:
RenderQuad (const Vec4& posA, const Vec4& posB)
: m_vertices(6)
{
m_vertices[0] = posA;
m_vertices[1] = Vec4(posA[0], posB[1], posA[2], posA[3]);
m_vertices[2] = posB;
m_vertices[3] = posB;
m_vertices[4] = Vec4(posB[0], posA[1], posB[2], posA[3]);
m_vertices[5] = posA;
}
const Vec4& getCornerA (void) const
{
return m_vertices[0];
}
const Vec4& getCornerB (void) const
{
return m_vertices[2];
}
const void* getVertexPointer (void) const
{
return &m_vertices[0];
}
size_t getVertexDataSize (void) const
{
return sizeof(Vec4) * m_vertices.size();
}
private:
vector<Vec4> m_vertices;
};
class ColorClear
{
public:
ColorClear (const UVec2& offset,
const UVec2& size,
const VkClearColorValue& color)
: m_offset (offset)
, m_size (size)
, m_color (color)
{
}
const UVec2& getOffset (void) const { return m_offset; }
const UVec2& getSize (void) const { return m_size; }
const VkClearColorValue& getColor (void) const { return m_color; }
private:
UVec2 m_offset;
UVec2 m_size;
VkClearColorValue m_color;
};
class DepthStencilClear
{
public:
DepthStencilClear (const UVec2& offset,
const UVec2& size,
float depth,
deUint32 stencil)
: m_offset (offset)
, m_size (size)
, m_depth (depth)
, m_stencil (stencil)
{
}
const UVec2& getOffset (void) const { return m_offset; }
const UVec2& getSize (void) const { return m_size; }
float getDepth (void) const { return m_depth; }
deUint32 getStencil (void) const { return m_stencil; }
private:
UVec2 m_offset;
UVec2 m_size;
float m_depth;
deUint32 m_stencil;
};
class SubpassRenderInfo
{
public:
SubpassRenderInfo (const RenderPass& renderPass,
deUint32 subpassIndex,
bool isSecondary_,
const UVec2& viewportOffset,
const UVec2& viewportSize,
const Maybe<RenderQuad>& renderQuad,
const vector<ColorClear>& colorClears,
const Maybe<DepthStencilClear>& depthStencilClear)
: m_viewportOffset (viewportOffset)
, m_viewportSize (viewportSize)
, m_subpassIndex (subpassIndex)
, m_isSecondary (isSecondary_)
, m_flags (renderPass.getSubpasses()[subpassIndex].getFlags())
, m_renderQuad (renderQuad)
, m_colorClears (colorClears)
, m_depthStencilClear (depthStencilClear)
, m_colorAttachments (renderPass.getSubpasses()[subpassIndex].getColorAttachments())
{
for (deUint32 attachmentNdx = 0; attachmentNdx < (deUint32)m_colorAttachments.size(); attachmentNdx++)
m_colorAttachmentInfo.push_back(renderPass.getAttachments()[m_colorAttachments[attachmentNdx].getAttachment()]);
if (renderPass.getSubpasses()[subpassIndex].getDepthStencilAttachment().getAttachment() != VK_ATTACHMENT_UNUSED)
{
m_depthStencilAttachment = tcu::just(renderPass.getSubpasses()[subpassIndex].getDepthStencilAttachment());
m_depthStencilAttachmentInfo = tcu::just(renderPass.getAttachments()[renderPass.getSubpasses()[subpassIndex].getDepthStencilAttachment().getAttachment()]);
}
}
const UVec2& getViewportOffset (void) const { return m_viewportOffset; }
const UVec2& getViewportSize (void) const { return m_viewportSize; }
deUint32 getSubpassIndex (void) const { return m_subpassIndex; }
bool isSecondary (void) const { return m_isSecondary; }
const Maybe<RenderQuad>& getRenderQuad (void) const { return m_renderQuad; }
const vector<ColorClear>& getColorClears (void) const { return m_colorClears; }
const Maybe<DepthStencilClear>& getDepthStencilClear (void) const { return m_depthStencilClear; }
deUint32 getColorAttachmentCount (void) const { return (deUint32)m_colorAttachments.size(); }
VkImageLayout getColorAttachmentLayout (deUint32 attachmentNdx) const { return m_colorAttachments[attachmentNdx].getImageLayout(); }
deUint32 getColorAttachmentIndex (deUint32 attachmentNdx) const { return m_colorAttachments[attachmentNdx].getAttachment(); }
const Attachment& getColorAttachment (deUint32 attachmentNdx) const { return m_colorAttachmentInfo[attachmentNdx]; }
Maybe<VkImageLayout> getDepthStencilAttachmentLayout (void) const { return m_depthStencilAttachment ? tcu::just(m_depthStencilAttachment->getImageLayout()) : tcu::nothing<VkImageLayout>(); }
Maybe<deUint32> getDepthStencilAttachmentIndex (void) const { return m_depthStencilAttachment ? tcu::just(m_depthStencilAttachment->getAttachment()) : tcu::nothing<deUint32>(); };
const Maybe<Attachment>& getDepthStencilAttachment (void) const { return m_depthStencilAttachmentInfo; }
VkSubpassDescriptionFlags getSubpassFlags (void) const { return m_flags; }
private:
UVec2 m_viewportOffset;
UVec2 m_viewportSize;
deUint32 m_subpassIndex;
bool m_isSecondary;
VkSubpassDescriptionFlags m_flags;
Maybe<RenderQuad> m_renderQuad;
vector<ColorClear> m_colorClears;
Maybe<DepthStencilClear> m_depthStencilClear;
vector<AttachmentReference> m_colorAttachments;
vector<Attachment> m_colorAttachmentInfo;
Maybe<AttachmentReference> m_depthStencilAttachment;
Maybe<Attachment> m_depthStencilAttachmentInfo;
};
Move<VkPipeline> createSubpassPipeline (const DeviceInterface& vk,
VkDevice device,
VkRenderPass renderPass,
VkShaderModule vertexShaderModule,
VkShaderModule fragmentShaderModule,
VkPipelineLayout pipelineLayout,
const SubpassRenderInfo& renderInfo)
{
const VkSpecializationInfo emptyShaderSpecializations =
{
0u, // mapEntryCount
DE_NULL, // pMap
0u, // dataSize
DE_NULL, // pData
};
Maybe<VkSampleCountFlagBits> rasterSamples;
vector<VkPipelineColorBlendAttachmentState> attachmentBlendStates;
for (deUint32 attachmentNdx = 0; attachmentNdx < renderInfo.getColorAttachmentCount(); attachmentNdx++)
{
const Attachment& attachment = renderInfo.getColorAttachment(attachmentNdx);
DE_ASSERT(!rasterSamples || *rasterSamples == attachment.getSamples());
rasterSamples = attachment.getSamples();
{
const VkPipelineColorBlendAttachmentState attachmentBlendState =
{
VK_FALSE, // blendEnable
VK_BLEND_FACTOR_SRC_ALPHA, // srcBlendColor
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, // destBlendColor
VK_BLEND_OP_ADD, // blendOpColor
VK_BLEND_FACTOR_ONE, // srcBlendAlpha
VK_BLEND_FACTOR_ONE, // destBlendAlpha
VK_BLEND_OP_ADD, // blendOpAlpha
VK_COLOR_COMPONENT_R_BIT|VK_COLOR_COMPONENT_G_BIT|VK_COLOR_COMPONENT_B_BIT|VK_COLOR_COMPONENT_A_BIT, // channelWriteMask
};
attachmentBlendStates.push_back(attachmentBlendState);
}
}
if (renderInfo.getDepthStencilAttachment())
{
const Attachment& attachment = *renderInfo.getDepthStencilAttachment();
DE_ASSERT(!rasterSamples || *rasterSamples == attachment.getSamples());
rasterSamples = attachment.getSamples();
}
// If there are no attachment use single sample
if (!rasterSamples)
rasterSamples = VK_SAMPLE_COUNT_1_BIT;
const VkPipelineShaderStageCreateInfo shaderStages[2] =
{
{
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // sType
DE_NULL, // pNext
(VkPipelineShaderStageCreateFlags)0u,
VK_SHADER_STAGE_VERTEX_BIT, // stage
vertexShaderModule, // shader
"main",
&emptyShaderSpecializations
},
{
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // sType
DE_NULL, // pNext
(VkPipelineShaderStageCreateFlags)0u,
VK_SHADER_STAGE_FRAGMENT_BIT, // stage
fragmentShaderModule, // shader
"main",
&emptyShaderSpecializations
}
};
const VkVertexInputBindingDescription vertexBinding =
{
0u, // binding
(deUint32)sizeof(tcu::Vec4), // strideInBytes
VK_VERTEX_INPUT_RATE_VERTEX, // stepRate
};
const VkVertexInputAttributeDescription vertexAttrib =
{
0u, // location
0u, // binding
VK_FORMAT_R32G32B32A32_SFLOAT, // format
0u, // offsetInBytes
};
const VkPipelineVertexInputStateCreateInfo vertexInputState =
{
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // sType
DE_NULL, // pNext
(VkPipelineVertexInputStateCreateFlags)0u,
1u, // bindingCount
&vertexBinding, // pVertexBindingDescriptions
1u, // attributeCount
&vertexAttrib, // pVertexAttributeDescriptions
};
const VkPipelineInputAssemblyStateCreateInfo inputAssemblyState =
{
VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // sType
DE_NULL, // pNext
(VkPipelineInputAssemblyStateCreateFlags)0u,
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // topology
VK_FALSE, // primitiveRestartEnable
};
const VkViewport viewport =
{
(float)renderInfo.getViewportOffset().x(), (float)renderInfo.getViewportOffset().y(),
(float)renderInfo.getViewportSize().x(), (float)renderInfo.getViewportSize().y(),
0.0f, 1.0f
};
const VkRect2D scissor =
{
{ (deInt32)renderInfo.getViewportOffset().x(), (deInt32)renderInfo.getViewportOffset().y() },
{ renderInfo.getViewportSize().x(), renderInfo.getViewportSize().y() }
};
const VkPipelineViewportStateCreateInfo viewportState =
{
VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
DE_NULL,
(VkPipelineViewportStateCreateFlags)0u,
1u,
&viewport,
1u,
&scissor
};
const VkPipelineRasterizationStateCreateInfo rasterState =
{
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // sType
DE_NULL, // pNext
(VkPipelineRasterizationStateCreateFlags)0u,
VK_TRUE, // depthClipEnable
VK_FALSE, // rasterizerDiscardEnable
VK_POLYGON_MODE_FILL, // fillMode
VK_CULL_MODE_NONE, // cullMode
VK_FRONT_FACE_COUNTER_CLOCKWISE, // frontFace
VK_FALSE, // depthBiasEnable
0.0f, // depthBias
0.0f, // depthBiasClamp
0.0f, // slopeScaledDepthBias
1.0f // lineWidth
};
const VkPipelineMultisampleStateCreateInfo multisampleState =
{
VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // sType
DE_NULL, // pNext
(VkPipelineMultisampleStateCreateFlags)0u,
*rasterSamples, // rasterSamples
VK_FALSE, // sampleShadingEnable
0.0f, // minSampleShading
DE_NULL, // pSampleMask
VK_FALSE, // alphaToCoverageEnable
VK_FALSE, // alphaToOneEnable
};
const VkPipelineDepthStencilStateCreateInfo depthStencilState =
{
VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // sType
DE_NULL, // pNext
(VkPipelineDepthStencilStateCreateFlags)0u,
VK_TRUE, // depthTestEnable
VK_TRUE, // depthWriteEnable
VK_COMPARE_OP_ALWAYS, // depthCompareOp
VK_FALSE, // depthBoundsEnable
VK_TRUE, // stencilTestEnable
{
VK_STENCIL_OP_REPLACE, // stencilFailOp
VK_STENCIL_OP_REPLACE, // stencilPassOp
VK_STENCIL_OP_REPLACE, // stencilDepthFailOp
VK_COMPARE_OP_ALWAYS, // stencilCompareOp
~0u, // stencilCompareMask
~0u, // stencilWriteMask
STENCIL_VALUE // stencilReference
}, // front
{
VK_STENCIL_OP_REPLACE, // stencilFailOp
VK_STENCIL_OP_REPLACE, // stencilPassOp
VK_STENCIL_OP_REPLACE, // stencilDepthFailOp
VK_COMPARE_OP_ALWAYS, // stencilCompareOp
~0u, // stencilCompareMask
~0u, // stencilWriteMask
STENCIL_VALUE // stencilReference
}, // back
0.0f, // minDepthBounds;
1.0f // maxDepthBounds;
};
const VkPipelineColorBlendStateCreateInfo blendState =
{
VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // sType
DE_NULL, // pNext
(VkPipelineColorBlendStateCreateFlags)0u,
VK_FALSE, // logicOpEnable
VK_LOGIC_OP_COPY, // logicOp
(deUint32)attachmentBlendStates.size(), // attachmentCount
attachmentBlendStates.empty() ? DE_NULL : &attachmentBlendStates[0],// pAttachments
{ 0.0f, 0.0f, 0.0f, 0.0f } // blendConst
};
const VkGraphicsPipelineCreateInfo createInfo =
{
VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // sType
DE_NULL, // pNext
(VkPipelineCreateFlags)0u,
2, // stageCount
shaderStages, // pStages
&vertexInputState, // pVertexInputState
&inputAssemblyState, // pInputAssemblyState
DE_NULL, // pTessellationState
&viewportState, // pViewportState
&rasterState, // pRasterState
&multisampleState, // pMultisampleState
&depthStencilState, // pDepthStencilState
&blendState, // pColorBlendState
(const VkPipelineDynamicStateCreateInfo*)DE_NULL, // pDynamicState
pipelineLayout, // layout
renderPass, // renderPass
renderInfo.getSubpassIndex(), // subpass
DE_NULL, // basePipelineHandle
0u // basePipelineIndex
};
return createGraphicsPipeline(vk, device, DE_NULL, &createInfo);
}
class SubpassRenderer
{
public:
SubpassRenderer (Context& context,
const DeviceInterface& vk,
VkDevice device,
Allocator& allocator,
VkRenderPass renderPass,
VkFramebuffer framebuffer,
VkCommandPool commandBufferPool,
deUint32 queueFamilyIndex,
const SubpassRenderInfo& renderInfo)
: m_renderInfo (renderInfo)
{
const deUint32 subpassIndex = renderInfo.getSubpassIndex();
if (renderInfo.getRenderQuad())
{
const RenderQuad& renderQuad = *renderInfo.getRenderQuad();
const VkPipelineLayoutCreateInfo pipelineLayoutParams =
{
VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // sType;
DE_NULL, // pNext;
(vk::VkPipelineLayoutCreateFlags)0,
0u, // descriptorSetCount;
DE_NULL, // pSetLayouts;
0u, // pushConstantRangeCount;
DE_NULL, // pPushConstantRanges;
};
m_vertexShaderModule = createShaderModule(vk, device, context.getBinaryCollection().get(de::toString(subpassIndex) + "-vert"), 0u);
m_fragmentShaderModule = createShaderModule(vk, device, context.getBinaryCollection().get(de::toString(subpassIndex) + "-frag"), 0u);
m_pipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutParams);
m_pipeline = createSubpassPipeline(vk, device, renderPass, *m_vertexShaderModule, *m_fragmentShaderModule, *m_pipelineLayout, m_renderInfo);
m_vertexBuffer = createBuffer(vk, device, 0u, (VkDeviceSize)renderQuad.getVertexDataSize(), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_SHARING_MODE_EXCLUSIVE, 1u, &queueFamilyIndex);
m_vertexBufferMemory = allocator.allocate(getBufferMemoryRequirements(vk, device, *m_vertexBuffer), MemoryRequirement::HostVisible);
bindBufferMemory(vk, device, *m_vertexBuffer, m_vertexBufferMemory->getMemory(), m_vertexBufferMemory->getOffset());
uploadBufferData(vk, device, *m_vertexBufferMemory, renderQuad.getVertexDataSize(), renderQuad.getVertexPointer());
}
if (renderInfo.isSecondary())
{
m_commandBuffer = allocateCommandBuffer(vk, device, commandBufferPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
beginCommandBuffer(vk, *m_commandBuffer, vk::VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, renderPass, subpassIndex, framebuffer, VK_FALSE, (VkQueryControlFlags)0, (VkQueryPipelineStatisticFlags)0);
pushRenderCommands(vk, *m_commandBuffer);
endCommandBuffer(vk, *m_commandBuffer);
}
}
bool isSecondary (void) const
{
return m_commandBuffer;
}
VkCommandBuffer getCommandBuffer (void) const
{
DE_ASSERT(isSecondary());
return *m_commandBuffer;
}
void pushRenderCommands (const DeviceInterface& vk,
VkCommandBuffer commandBuffer)
{
if (!m_renderInfo.getColorClears().empty())
{
const vector<ColorClear>& colorClears (m_renderInfo.getColorClears());
for (deUint32 attachmentNdx = 0; attachmentNdx < m_renderInfo.getColorAttachmentCount(); attachmentNdx++)
{
const ColorClear& colorClear = colorClears[attachmentNdx];
const VkClearAttachment attachment =
{
VK_IMAGE_ASPECT_COLOR_BIT,
attachmentNdx,
makeClearValue(colorClear.getColor()),
};
const VkClearRect rect =
{
{
{ (deInt32)colorClear.getOffset().x(), (deInt32)colorClear.getOffset().y() },
{ colorClear.getSize().x(), colorClear.getSize().y() }
}, // rect
0u, // baseArrayLayer
1u, // layerCount
};
vk.cmdClearAttachments(commandBuffer, 1u, &attachment, 1u, &rect);
}
}
if (m_renderInfo.getDepthStencilClear())
{
const DepthStencilClear& depthStencilClear = *m_renderInfo.getDepthStencilClear();
const deUint32 attachmentNdx = m_renderInfo.getColorAttachmentCount();
tcu::TextureFormat format = mapVkFormat(m_renderInfo.getDepthStencilAttachment()->getFormat());
const VkClearAttachment attachment =
{
(VkImageAspectFlags)((hasDepthComponent(format.order) ? VK_IMAGE_ASPECT_DEPTH_BIT : 0)
| (hasStencilComponent(format.order) ? VK_IMAGE_ASPECT_STENCIL_BIT : 0)),
attachmentNdx,
makeClearValueDepthStencil(depthStencilClear.getDepth(), depthStencilClear.getStencil())
};
const VkClearRect rect =
{
{
{ (deInt32)depthStencilClear.getOffset().x(), (deInt32)depthStencilClear.getOffset().y() },
{ depthStencilClear.getSize().x(), depthStencilClear.getSize().y() }
}, // rect
0u, // baseArrayLayer
1u, // layerCount
};
vk.cmdClearAttachments(commandBuffer, 1u, &attachment, 1u, &rect);
}
if (m_renderInfo.getRenderQuad())
{
const VkDeviceSize offset = 0;
const VkBuffer vertexBuffer = *m_vertexBuffer;
vk.cmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
vk.cmdBindVertexBuffers(commandBuffer, 0u, 1u, &vertexBuffer, &offset);
vk.cmdDraw(commandBuffer, 6u, 1u, 0u, 0u);
}
}
private:
const SubpassRenderInfo m_renderInfo;
Move<VkCommandBuffer> m_commandBuffer;
Move<VkPipeline> m_pipeline;
Move<VkPipelineLayout> m_pipelineLayout;
Move<VkShaderModule> m_vertexShaderModule;
Move<VkShaderModule> m_fragmentShaderModule;
Move<VkBuffer> m_vertexBuffer;
de::MovePtr<Allocation> m_vertexBufferMemory;
};
void pushImageInitializationCommands (const DeviceInterface& vk,
VkCommandBuffer commandBuffer,
const vector<Attachment>& attachmentInfo,
const vector<de::SharedPtr<AttachmentResources> >& attachmentResources,
deUint32 queueIndex,
const vector<Maybe<VkClearValue> >& clearValues)
{
{
vector<VkImageMemoryBarrier> initializeLayouts;
for (size_t attachmentNdx = 0; attachmentNdx < attachmentInfo.size(); attachmentNdx++)
{
if (!clearValues[attachmentNdx])
continue;
const VkImageMemoryBarrier barrier =
{
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType;
DE_NULL, // pNext;
(VkAccessFlags)0, // srcAccessMask
getAllMemoryReadFlags() | VK_ACCESS_TRANSFER_WRITE_BIT, // dstAccessMask
VK_IMAGE_LAYOUT_UNDEFINED, // oldLayout
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // newLayout;
queueIndex, // srcQueueFamilyIndex;
queueIndex, // destQueueFamilyIndex;
attachmentResources[attachmentNdx]->getImage(), // image;
{ // subresourceRange;
getImageAspectFlags(attachmentInfo[attachmentNdx].getFormat()), // aspect;
0, // baseMipLevel;
1, // mipLevels;
0, // baseArraySlice;
1 // arraySize;
}
};
initializeLayouts.push_back(barrier);
}
if (!initializeLayouts.empty())
vk.cmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, (VkDependencyFlags)0,
0, (const VkMemoryBarrier*)DE_NULL,
0, (const VkBufferMemoryBarrier*)DE_NULL,
(deUint32)initializeLayouts.size(), &initializeLayouts[0]);
}
for (size_t attachmentNdx = 0; attachmentNdx < attachmentInfo.size(); attachmentNdx++)
{
if (!clearValues[attachmentNdx])
continue;
const tcu::TextureFormat format = mapVkFormat(attachmentInfo[attachmentNdx].getFormat());
if (hasStencilComponent(format.order) || hasDepthComponent(format.order))
{
const float clearNan = tcu::Float32::nan().asFloat();
const float clearDepth = hasDepthComponent(format.order) ? clearValues[attachmentNdx]->depthStencil.depth : clearNan;
const deUint32 clearStencil = hasStencilComponent(format.order) ? clearValues[attachmentNdx]->depthStencil.stencil : ~0u;
const VkClearDepthStencilValue depthStencil =
{
clearDepth,
clearStencil
};
const VkImageSubresourceRange range =
{
(VkImageAspectFlags)((hasDepthComponent(format.order) ? VK_IMAGE_ASPECT_DEPTH_BIT : 0)
| (hasStencilComponent(format.order) ? VK_IMAGE_ASPECT_STENCIL_BIT : 0)),
0,
1,
0,
1
};
vk.cmdClearDepthStencilImage(commandBuffer, attachmentResources[attachmentNdx]->getImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &depthStencil, 1, &range);
}
else
{
const VkImageSubresourceRange range =
{
VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask;
0, // baseMipLevel;
1, // mipLevels;
0, // baseArrayLayer;
1 // layerCount;
};
const VkClearColorValue clearColor = clearValues[attachmentNdx]->color;
vk.cmdClearColorImage(commandBuffer, attachmentResources[attachmentNdx]->getImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColor, 1, &range);
}
}
{
vector<VkImageMemoryBarrier> renderPassLayouts;
for (size_t attachmentNdx = 0; attachmentNdx < attachmentInfo.size(); attachmentNdx++)
{
const VkImageLayout oldLayout = clearValues[attachmentNdx] ? VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
const VkImageMemoryBarrier barrier =
{
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType;
DE_NULL, // pNext;
(oldLayout != VK_IMAGE_LAYOUT_UNDEFINED ? getAllMemoryWriteFlags() : (VkAccessFlags)0), // srcAccessMask
getAllMemoryReadFlags() | getMemoryFlagsForLayout(attachmentInfo[attachmentNdx].getInitialLayout()), // dstAccessMask
oldLayout, // oldLayout
attachmentInfo[attachmentNdx].getInitialLayout(), // newLayout;
queueIndex, // srcQueueFamilyIndex;
queueIndex, // destQueueFamilyIndex;
attachmentResources[attachmentNdx]->getImage(), // image;
{ // subresourceRange;
getImageAspectFlags(attachmentInfo[attachmentNdx].getFormat()), // aspect;
0, // baseMipLevel;
1, // mipLevels;
0, // baseArraySlice;
1 // arraySize;
}
};
renderPassLayouts.push_back(barrier);
}
if (!renderPassLayouts.empty())
vk.cmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, (VkDependencyFlags)0,
0, (const VkMemoryBarrier*)DE_NULL,
0, (const VkBufferMemoryBarrier*)DE_NULL,
(deUint32)renderPassLayouts.size(), &renderPassLayouts[0]);
}
}
void pushRenderPassCommands (const DeviceInterface& vk,
VkCommandBuffer commandBuffer,
VkRenderPass renderPass,
VkFramebuffer framebuffer,
const vector<de::SharedPtr<SubpassRenderer> >& subpassRenderers,
const UVec2& renderPos,
const UVec2& renderSize,
const vector<Maybe<VkClearValue> >& renderPassClearValues,
TestConfig::RenderTypes render)
{
const float clearNan = tcu::Float32::nan().asFloat();
vector<VkClearValue> attachmentClearValues;
for (size_t attachmentNdx = 0; attachmentNdx < renderPassClearValues.size(); attachmentNdx++)
{
if (renderPassClearValues[attachmentNdx])
attachmentClearValues.push_back(*renderPassClearValues[attachmentNdx]);
else
attachmentClearValues.push_back(makeClearValueColorF32(clearNan, clearNan, clearNan, clearNan));
}
{
const VkRect2D renderArea =
{
{ (deInt32)renderPos.x(), (deInt32)renderPos.y() },
{ renderSize.x(), renderSize.y() }
};
for (size_t subpassNdx = 0; subpassNdx < subpassRenderers.size(); subpassNdx++)
{
const VkSubpassContents contents = subpassRenderers[subpassNdx]->isSecondary() ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS : VK_SUBPASS_CONTENTS_INLINE;
if (subpassNdx == 0)
cmdBeginRenderPass(vk, commandBuffer, renderPass, framebuffer, renderArea, (deUint32)attachmentClearValues.size(), attachmentClearValues.empty() ? DE_NULL : &attachmentClearValues[0], contents);
else
vk.cmdNextSubpass(commandBuffer, contents);
if (render)
{
if (contents == VK_SUBPASS_CONTENTS_INLINE)
{
subpassRenderers[subpassNdx]->pushRenderCommands(vk, commandBuffer);
}
else if (contents == VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS)
{
const VkCommandBuffer cmd = subpassRenderers[subpassNdx]->getCommandBuffer();
vk.cmdExecuteCommands(commandBuffer, 1, &cmd);
}
else
DE_FATAL("Invalid contents");
}
}
vk.cmdEndRenderPass(commandBuffer);
}
}
void pushReadImagesToBuffers (const DeviceInterface& vk,
VkCommandBuffer commandBuffer,
deUint32 queueIndex,
const vector<de::SharedPtr<AttachmentResources> >& attachmentResources,
const vector<Attachment>& attachmentInfo,
const vector<bool>& isLazy,
const UVec2& targetSize)
{
{
vector<VkImageMemoryBarrier> imageBarriers;
for (size_t attachmentNdx = 0; attachmentNdx < attachmentInfo.size(); attachmentNdx++)
{
if (isLazy[attachmentNdx])
continue;
const VkImageLayout oldLayout = attachmentInfo[attachmentNdx].getFinalLayout();
const VkImageMemoryBarrier barrier =
{
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType
DE_NULL, // pNext
getAllMemoryWriteFlags() | getMemoryFlagsForLayout(oldLayout), // srcAccessMask
getAllMemoryReadFlags(), // dstAccessMask
oldLayout, // oldLayout
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // newLayout
queueIndex, // srcQueueFamilyIndex
queueIndex, // destQueueFamilyIndex
attachmentResources[attachmentNdx]->getImage(), // image
{ // subresourceRange
getImageAspectFlags(attachmentInfo[attachmentNdx].getFormat()), // aspect;
0, // baseMipLevel
1, // mipLevels
0, // baseArraySlice
1 // arraySize
}
};
imageBarriers.push_back(barrier);
}
if (!imageBarriers.empty())
vk.cmdPipelineBarrier(commandBuffer,
getAllPipelineStageFlags(),
getAllPipelineStageFlags(),
(VkDependencyFlags)0,
0, (const VkMemoryBarrier*)DE_NULL,
0, (const VkBufferMemoryBarrier*)DE_NULL,
(deUint32)imageBarriers.size(), &imageBarriers[0]);
}
for (size_t attachmentNdx = 0; attachmentNdx < attachmentInfo.size(); attachmentNdx++)
{
if (isLazy[attachmentNdx])
continue;
const tcu::TextureFormat::ChannelOrder order = mapVkFormat(attachmentInfo[attachmentNdx].getFormat()).order;
const VkBufferImageCopy rect =
{
0, // bufferOffset
0, // bufferRowLength
0, // bufferImageHeight
{ // imageSubresource
(vk::VkImageAspectFlags)getPrimaryImageAspect(mapVkFormat(attachmentInfo[attachmentNdx].getFormat()).order), // aspect
0, // mipLevel
0, // arraySlice
1 // arraySize
},
{ 0, 0, 0 }, // imageOffset
{ targetSize.x(), targetSize.y(), 1u } // imageExtent
};
vk.cmdCopyImageToBuffer(commandBuffer, attachmentResources[attachmentNdx]->getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, attachmentResources[attachmentNdx]->getBuffer(), 1, &rect);
if (tcu::TextureFormat::DS == order)
{
const VkBufferImageCopy stencilRect =
{
0, // bufferOffset
0, // bufferRowLength
0, // bufferImageHeight
{ // imageSubresource
VK_IMAGE_ASPECT_STENCIL_BIT, // aspect
0, // mipLevel
0, // arraySlice
1 // arraySize
},
{ 0, 0, 0 }, // imageOffset
{ targetSize.x(), targetSize.y(), 1u } // imageExtent
};
vk.cmdCopyImageToBuffer(commandBuffer, attachmentResources[attachmentNdx]->getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, attachmentResources[attachmentNdx]->getSecondaryBuffer(), 1, &stencilRect);
}
}
{
vector<VkBufferMemoryBarrier> bufferBarriers;
for (size_t attachmentNdx = 0; attachmentNdx < attachmentInfo.size(); attachmentNdx++)
{
if (isLazy[attachmentNdx])
continue;
const tcu::TextureFormat::ChannelOrder order = mapVkFormat(attachmentInfo[attachmentNdx].getFormat()).order;
const VkBufferMemoryBarrier bufferBarrier =
{
VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
DE_NULL,
getAllMemoryWriteFlags(),
getAllMemoryReadFlags(),
queueIndex,
queueIndex,
attachmentResources[attachmentNdx]->getBuffer(),
0,
attachmentResources[attachmentNdx]->getBufferSize()
};
bufferBarriers.push_back(bufferBarrier);
if (tcu::TextureFormat::DS == order)
{
const VkBufferMemoryBarrier secondaryBufferBarrier =
{
VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
DE_NULL,
getAllMemoryWriteFlags(),
getAllMemoryReadFlags(),
queueIndex,
queueIndex,
attachmentResources[attachmentNdx]->getSecondaryBuffer(),
0,
attachmentResources[attachmentNdx]->getSecondaryBufferSize()
};
bufferBarriers.push_back(secondaryBufferBarrier);
}
}
if (!bufferBarriers.empty())
vk.cmdPipelineBarrier(commandBuffer,
getAllPipelineStageFlags(),
getAllPipelineStageFlags(),
(VkDependencyFlags)0,
0, (const VkMemoryBarrier*)DE_NULL,
(deUint32)bufferBarriers.size(), &bufferBarriers[0],
0, (const VkImageMemoryBarrier*)DE_NULL);
}
}
void clear (const PixelBufferAccess& access, const VkClearValue& value)
{
const tcu::TextureFormat& format = access.getFormat();
if (tcu::hasDepthComponent(format.order) || tcu::hasStencilComponent(format.order))
{
if (tcu::hasDepthComponent(format.order))
tcu::clearDepth(access, value.depthStencil.depth);
if (tcu::hasStencilComponent(format.order))
tcu::clearStencil(access, value.depthStencil.stencil);
}
else
{
if (tcu::getTextureChannelClass(format.type) == tcu::TEXTURECHANNELCLASS_FLOATING_POINT
|| tcu::getTextureChannelClass(format.type) == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT
|| tcu::getTextureChannelClass(format.type) == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
{
const tcu::Vec4 color (value.color.float32[0],
value.color.float32[1],
value.color.float32[2],
value.color.float32[3]);
if (tcu::isSRGB(format))
tcu::clear(access, tcu::linearToSRGB(color));
else
tcu::clear(access, color);
}
else if (tcu::getTextureChannelClass(format.type) == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER)
{
const tcu::UVec4 color (value.color.uint32[0],
value.color.uint32[1],
value.color.uint32[2],
value.color.uint32[3]);
tcu::clear(access, color);
}
else if (tcu::getTextureChannelClass(format.type) == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER)
{
const tcu::IVec4 color (value.color.int32[0],
value.color.int32[1],
value.color.int32[2],
value.color.int32[3]);
tcu::clear(access, color);
}
else
DE_FATAL("Unknown channel class");
}
}
Vec4 computeUvs (const IVec2& posA, const IVec2& posB, const IVec2& pos)
{
const float u = de::clamp((float)(pos.x() - posA.x()) / (float)(posB.x() - posA.x()), 0.0f, 1.0f);
const float v = de::clamp((float)(pos.y() - posA.y()) / (float)(posB.y() - posA.y()), 0.0f, 1.0f);
return Vec4(u, v, u * v, (u + v) / 2.0f);
}
void renderReferenceImages (vector<tcu::TextureLevel>& referenceAttachments,
const RenderPass& renderPassInfo,
const UVec2& targetSize,
const vector<Maybe<VkClearValue> >& imageClearValues,
const vector<Maybe<VkClearValue> >& renderPassClearValues,
const vector<SubpassRenderInfo>& subpassRenderInfo,
const UVec2& renderPos,
const UVec2& renderSize)
{
const vector<Subpass>& subpasses = renderPassInfo.getSubpasses();
vector<bool> attachmentUsed (renderPassInfo.getAttachments().size(), false);
referenceAttachments.resize(renderPassInfo.getAttachments().size());
for (size_t attachmentNdx = 0; attachmentNdx < renderPassInfo.getAttachments().size(); attachmentNdx++)
{
const Attachment attachment = renderPassInfo.getAttachments()[attachmentNdx];
const tcu::TextureFormat format = mapVkFormat(attachment.getFormat());
const tcu::TextureFormatInfo textureInfo = tcu::getTextureFormatInfo(format);
tcu::TextureLevel& reference = referenceAttachments[attachmentNdx];
const bool isDepthOrStencilAttachment = hasDepthComponent(format.order) || hasStencilComponent(format.order);
reference = tcu::TextureLevel(format, targetSize.x(), targetSize.y());
if (imageClearValues[attachmentNdx])
clear(reference.getAccess(), *imageClearValues[attachmentNdx]);
else
{
// Fill with grid if image contentst are undefined before renderpass
if (isDepthOrStencilAttachment)
{
if (tcu::hasDepthComponent(format.order))
tcu::fillWithGrid(tcu::getEffectiveDepthStencilAccess(reference.getAccess(), tcu::Sampler::MODE_DEPTH), 2, textureInfo.valueMin, textureInfo.valueMax);
if (tcu::hasStencilComponent(format.order))
tcu::fillWithGrid(tcu::getEffectiveDepthStencilAccess(reference.getAccess(), tcu::Sampler::MODE_STENCIL), 2, textureInfo.valueMin, textureInfo.valueMax);
}
else
tcu::fillWithGrid(reference.getAccess(), 2, textureInfo.valueMin, textureInfo.valueMax);
}
}
for (size_t subpassNdx = 0; subpassNdx < subpasses.size(); subpassNdx++)
{
const Subpass& subpass = subpasses[subpassNdx];
const SubpassRenderInfo& renderInfo = subpassRenderInfo[subpassNdx];
const vector<AttachmentReference>& colorAttachments = subpass.getColorAttachments();
// Apply load op if attachment was used for the first time
for (size_t attachmentNdx = 0; attachmentNdx < colorAttachments.size(); attachmentNdx++)
{
const deUint32 attachmentIndex = colorAttachments[attachmentNdx].getAttachment();
if (!attachmentUsed[attachmentIndex])
{
const Attachment& attachment = renderPassInfo.getAttachments()[attachmentIndex];
tcu::TextureLevel& reference = referenceAttachments[attachmentIndex];
DE_ASSERT(!tcu::hasDepthComponent(reference.getFormat().order));
DE_ASSERT(!tcu::hasStencilComponent(reference.getFormat().order));
if (attachment.getLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR)
clear(tcu::getSubregion(reference.getAccess(), renderPos.x(), renderPos.y(), renderSize.x(), renderSize.y()), *renderPassClearValues[attachmentIndex]);
else if (attachment.getLoadOp() == VK_ATTACHMENT_LOAD_OP_DONT_CARE)
{
const tcu::TextureFormatInfo textureInfo = tcu::getTextureFormatInfo(reference.getFormat());
tcu::fillWithGrid(tcu::getSubregion(reference.getAccess(), renderPos.x(), renderPos.y(), renderSize.x(), renderSize.y()), 2, textureInfo.valueMin, textureInfo.valueMax);
}
attachmentUsed[attachmentIndex] = true;
}
}
// Apply load op to depth/stencil attachment if it was used for the first time
if (subpass.getDepthStencilAttachment().getAttachment() != VK_ATTACHMENT_UNUSED && !attachmentUsed[subpass.getDepthStencilAttachment().getAttachment()])
{
const deUint32 attachmentIndex = subpass.getDepthStencilAttachment().getAttachment();
// Apply load op if attachment was used for the first time
if (!attachmentUsed[attachmentIndex])
{
const Attachment& attachment = renderPassInfo.getAttachments()[attachmentIndex];
tcu::TextureLevel& reference = referenceAttachments[attachmentIndex];
if (tcu::hasDepthComponent(reference.getFormat().order))
{
if (attachment.getLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR)
clear(tcu::getSubregion(tcu::getEffectiveDepthStencilAccess(reference.getAccess(), tcu::Sampler::MODE_DEPTH), renderPos.x(), renderPos.y(), renderSize.x(), renderSize.y()), *renderPassClearValues[attachmentIndex]);
else if (attachment.getLoadOp() == VK_ATTACHMENT_LOAD_OP_DONT_CARE)
{
const tcu::TextureFormatInfo textureInfo = tcu::getTextureFormatInfo(reference.getFormat());
tcu::fillWithGrid(tcu::getSubregion(tcu::getEffectiveDepthStencilAccess(reference.getAccess(), tcu::Sampler::MODE_DEPTH), renderPos.x(), renderPos.y(), renderSize.x(), renderSize.y()), 2, textureInfo.valueMin, textureInfo.valueMax);
}
}
if (tcu::hasStencilComponent(reference.getFormat().order))
{
if (attachment.getStencilLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR)
clear(tcu::getSubregion(tcu::getEffectiveDepthStencilAccess(reference.getAccess(), tcu::Sampler::MODE_STENCIL), renderPos.x(), renderPos.y(), renderSize.x(), renderSize.y()), *renderPassClearValues[attachmentIndex]);
else if (attachment.getStencilLoadOp() == VK_ATTACHMENT_LOAD_OP_DONT_CARE)
{
const tcu::TextureFormatInfo textureInfo = tcu::getTextureFormatInfo(reference.getFormat());
tcu::fillWithGrid(tcu::getSubregion(tcu::getEffectiveDepthStencilAccess(reference.getAccess(), tcu::Sampler::MODE_STENCIL), renderPos.x(), renderPos.y(), renderSize.x(), renderSize.y()), 2, textureInfo.valueMin, textureInfo.valueMax);
}
}
}
attachmentUsed[attachmentIndex] = true;
}
for (size_t colorClearNdx = 0; colorClearNdx < renderInfo.getColorClears().size(); colorClearNdx++)
{
const ColorClear& colorClear = renderInfo.getColorClears()[colorClearNdx];
const UVec2 offset = colorClear.getOffset();
const UVec2 size = colorClear.getSize();
tcu::TextureLevel& reference = referenceAttachments[subpass.getColorAttachments()[colorClearNdx].getAttachment()];
VkClearValue value;
value.color = colorClear.getColor();
clear(tcu::getSubregion(reference.getAccess(), offset.x(), offset.y(), 0, size.x(), size.y(), 1), value);
}
if (renderInfo.getDepthStencilClear())
{
const DepthStencilClear& dsClear = *renderInfo.getDepthStencilClear();
const UVec2 offset = dsClear.getOffset();
const UVec2 size = dsClear.getSize();
tcu::TextureLevel& reference = referenceAttachments[subpass.getDepthStencilAttachment().getAttachment()];
if (tcu::hasDepthComponent(reference.getFormat().order))
clearDepth(tcu::getSubregion(reference.getAccess(), offset.x(), offset.y(), 0, size.x(), size.y(), 1), dsClear.getDepth());
if (tcu::hasStencilComponent(reference.getFormat().order))
clearStencil(tcu::getSubregion(reference.getAccess(), offset.x(), offset.y(), 0, size.x(), size.y(), 1), dsClear.getStencil());
}
if (renderInfo.getRenderQuad())
{
const RenderQuad& renderQuad = *renderInfo.getRenderQuad();
const Vec4 posA = renderQuad.getCornerA();
const Vec4 posB = renderQuad.getCornerB();
const Vec2 origin = Vec2((float)renderInfo.getViewportOffset().x(), (float)renderInfo.getViewportOffset().y()) + Vec2((float)renderInfo.getViewportSize().x(), (float)renderInfo.getViewportSize().y()) / Vec2(2.0f);
const Vec2 p = Vec2((float)renderInfo.getViewportSize().x(), (float)renderInfo.getViewportSize().y()) / Vec2(2.0f);
const IVec2 posAI ((deInt32)(origin.x() + (p.x() * posA.x())),
(deInt32)(origin.y() + (p.y() * posA.y())));
const IVec2 posBI ((deInt32)(origin.x() + (p.x() * posB.x())),
(deInt32)(origin.y() + (p.y() * posB.y())));
for (size_t attachmentRefNdx = 0; attachmentRefNdx < subpass.getColorAttachments().size(); attachmentRefNdx++)
{
const Attachment attachment = renderPassInfo.getAttachments()[subpass.getColorAttachments()[attachmentRefNdx].getAttachment()];
const tcu::TextureFormatInfo textureInfo = tcu::getTextureFormatInfo(mapVkFormat(attachment.getFormat()));
tcu::TextureLevel& referenceTexture = referenceAttachments[subpass.getColorAttachments()[attachmentRefNdx].getAttachment()];
const bool srgb = tcu::isSRGB(referenceTexture.getFormat());
const PixelBufferAccess reference = referenceTexture.getAccess();
const float clampMin = (float)(-MAX_INTEGER_VALUE);
const float clampMax = (float)(MAX_INTEGER_VALUE);
const Vec4 valueMax (de::clamp(textureInfo.valueMax[0], clampMin, clampMax),
de::clamp(textureInfo.valueMax[1], clampMin, clampMax),
de::clamp(textureInfo.valueMax[2], clampMin, clampMax),
de::clamp(textureInfo.valueMax[3], clampMin, clampMax));
const Vec4 valueMin (de::clamp(textureInfo.valueMin[0], clampMin, clampMax),
de::clamp(textureInfo.valueMin[1], clampMin, clampMax),
de::clamp(textureInfo.valueMin[2], clampMin, clampMax),
de::clamp(textureInfo.valueMin[3], clampMin, clampMax));
DE_ASSERT(posAI.x() < posBI.x());
DE_ASSERT(posAI.y() < posBI.y());
for (int y = posAI.y(); y <= (int)posBI.y(); y++)
for (int x = posAI.x(); x <= (int)posBI.x(); x++)
{
const Vec4 uvs = computeUvs(posAI, posBI, IVec2(x, y));
const Vec4 color = valueMax * uvs + valueMin * (Vec4(1.0f) - uvs);
if (srgb)
reference.setPixel(tcu::linearToSRGB(color), x, y);
else
reference.setPixel(color, x, y);
}
}
if (subpass.getDepthStencilAttachment().getAttachment() != VK_ATTACHMENT_UNUSED)
{
tcu::TextureLevel& referenceTexture = referenceAttachments[subpass.getDepthStencilAttachment().getAttachment()];
const PixelBufferAccess reference = referenceTexture.getAccess();
DE_ASSERT(posAI.x() < posBI.x());
DE_ASSERT(posAI.y() < posBI.y());
for (int y = posAI.y(); y <= (int)posBI.y(); y++)
for (int x = posAI.x(); x <= (int)posBI.x(); x++)
{
const Vec4 uvs = computeUvs(posAI, posBI, IVec2(x, y));
if (tcu::hasDepthComponent(reference.getFormat().order))
reference.setPixDepth(uvs.x(), x, y);
if (tcu::hasStencilComponent(reference.getFormat().order))
reference.setPixStencil(STENCIL_VALUE, x, y);
}
}
}
}
// Mark all attachments that were used but not stored as undefined
for (size_t attachmentNdx = 0; attachmentNdx < renderPassInfo.getAttachments().size(); attachmentNdx++)
{
const Attachment attachment = renderPassInfo.getAttachments()[attachmentNdx];
const tcu::TextureFormat format = mapVkFormat(attachment.getFormat());
const tcu::TextureFormatInfo textureInfo = tcu::getTextureFormatInfo(format);
tcu::TextureLevel& reference = referenceAttachments[attachmentNdx];
if (attachmentUsed[attachmentNdx] && renderPassInfo.getAttachments()[attachmentNdx].getStoreOp() == VK_ATTACHMENT_STORE_OP_DONT_CARE)
tcu::fillWithGrid(tcu::getSubregion(reference.getAccess(), renderPos.x(), renderPos.y(), renderSize.x(), renderSize.y()), 2, textureInfo.valueMin, textureInfo.valueMax);
}
}
Maybe<deUint32> findColorAttachment (const Subpass& subpass,
deUint32 attachmentIndex)
{
for (size_t colorAttachmentNdx = 0; colorAttachmentNdx < subpass.getColorAttachments().size(); colorAttachmentNdx++)
{
if (subpass.getColorAttachments()[colorAttachmentNdx].getAttachment() == attachmentIndex)
return tcu::just((deUint32)colorAttachmentNdx);
}
return tcu::nothing<deUint32>();
}
int calcFloatDiff (float a, float b)
{
const deUint32 au = tcu::Float32(a).bits();
const deUint32 bu = tcu::Float32(b).bits();
const bool asign = (au & (0x1u << 31u)) != 0u;
const bool bsign = (bu & (0x1u << 31u)) != 0u;
const deUint32 avalue = (au & ((0x1u << 31u) - 1u));
const deUint32 bvalue = (bu & ((0x1u << 31u) - 1u));
if (asign != bsign)
return avalue + bvalue + 1u;
else if (avalue < bvalue)
return bvalue - avalue;
else
return avalue - bvalue;
}
bool comparePixelToDepthClearValue (const ConstPixelBufferAccess& access,
int x,
int y,
float ref)
{
const tcu::TextureFormat format = tcu::getEffectiveDepthStencilTextureFormat(access.getFormat(), tcu::Sampler::MODE_DEPTH);
const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(format.type);
switch (channelClass)
{
case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
{
const int bitDepth = tcu::getTextureFormatBitDepth(format).x();
const float depth = access.getPixDepth(x, y);
const float threshold = 2.0f / (float)((1 << bitDepth) - 1);
return deFloatAbs(depth - ref) <= threshold;
}
case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
{
const float depth = access.getPixDepth(x, y);
const int mantissaBits = tcu::getTextureFormatMantissaBitDepth(format).x();
const int threshold = 10 * 1 << (23 - mantissaBits);
DE_ASSERT(mantissaBits <= 23);
return calcFloatDiff(depth, ref) <= threshold;
}
default:
DE_FATAL("Invalid channel class");
return false;
}
}
bool comparePixelToStencilClearValue (const ConstPixelBufferAccess& access,
int x,
int y,
deUint32 ref)
{
const deUint32 stencil = access.getPixStencil(x, y);
return stencil == ref;
}
bool comparePixelToColorClearValue (const ConstPixelBufferAccess& access,
int x,
int y,
const VkClearColorValue& ref)
{
const tcu::TextureFormat format = access.getFormat();
const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(format.type);
const BVec4 channelMask = tcu::getTextureFormatChannelMask(format);
switch (channelClass)
{
case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
{
const IVec4 bitDepth (tcu::getTextureFormatBitDepth(format));
const Vec4 resColor (access.getPixel(x, y));
const Vec4 refColor (ref.float32[0],
ref.float32[1],
ref.float32[2],
ref.float32[3]);
const Vec4 threshold (bitDepth[0] > 0 ? 20.0f / (float)((1 << bitDepth[0]) - 1) : 1.0f,
bitDepth[1] > 0 ? 20.0f / (float)((1 << bitDepth[1]) - 1) : 1.0f,
bitDepth[2] > 0 ? 20.0f / (float)((1 << bitDepth[2]) - 1) : 1.0f,
bitDepth[3] > 0 ? 20.0f / (float)((1 << bitDepth[3]) - 1) : 1.0f);
if (tcu::isSRGB(access.getFormat()))
return !(tcu::anyNotEqual(tcu::logicalAnd(lessThanEqual(tcu::absDiff(resColor, tcu::linearToSRGB(refColor)), threshold), channelMask), channelMask));
else
return !(tcu::anyNotEqual(tcu::logicalAnd(lessThanEqual(tcu::absDiff(resColor, refColor), threshold), channelMask), channelMask));
}
case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
{
const UVec4 resColor (access.getPixelUint(x, y));
const UVec4 refColor (ref.uint32[0],
ref.uint32[1],
ref.uint32[2],
ref.uint32[3]);
const UVec4 threshold (1);
return !(tcu::anyNotEqual(tcu::logicalAnd(lessThanEqual(tcu::absDiff(resColor, refColor), threshold), channelMask), channelMask));
}
case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
{
const IVec4 resColor (access.getPixelInt(x, y));
const IVec4 refColor (ref.int32[0],
ref.int32[1],
ref.int32[2],
ref.int32[3]);
const IVec4 threshold (1);
return !(tcu::anyNotEqual(tcu::logicalAnd(lessThanEqual(tcu::absDiff(resColor, refColor), threshold), channelMask), channelMask));
}
case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
{
const Vec4 resColor (access.getPixel(x, y));
const Vec4 refColor (ref.float32[0],
ref.float32[1],
ref.float32[2],
ref.float32[3]);
const IVec4 mantissaBits (tcu::getTextureFormatMantissaBitDepth(format));
const IVec4 threshold (10 * IVec4(1) << (23 - mantissaBits));
DE_ASSERT(tcu::allEqual(greaterThanEqual(threshold, IVec4(0)), BVec4(true)));
for (int ndx = 0; ndx < 4; ndx++)
{
if (calcFloatDiff(resColor[ndx], refColor[ndx]) > threshold[ndx] && channelMask[ndx])
return false;
}
return true;
}
default:
DE_FATAL("Invalid channel class");
return false;
}
}
class PixelStatus
{
public:
enum Status
{
STATUS_UNDEFINED = 0,
STATUS_OK = 1,
STATUS_FAIL = 2,
STATUS_LAST
};
PixelStatus (Status color, Status depth, Status stencil)
: m_status ((deUint8)((color << COLOR_OFFSET)
| (depth << DEPTH_OFFSET)
| (stencil << STENCIL_OFFSET)))
{
}
Status getColorStatus (void) const { return (Status)((m_status & COLOR_MASK) >> COLOR_OFFSET); }
Status getDepthStatus (void) const { return (Status)((m_status & DEPTH_MASK) >> DEPTH_OFFSET); }
Status getStencilStatus (void) const { return (Status)((m_status & STENCIL_MASK) >> STENCIL_OFFSET); }
void setColorStatus (Status status)
{
DE_ASSERT(getColorStatus() == STATUS_UNDEFINED);
m_status |= (deUint8)(status << COLOR_OFFSET);
}
void setDepthStatus (Status status)
{
DE_ASSERT(getDepthStatus() == STATUS_UNDEFINED);
m_status |= (deUint8)(status << DEPTH_OFFSET);
}
void setStencilStatus (Status status)
{
DE_ASSERT(getStencilStatus() == STATUS_UNDEFINED);
m_status |= (deUint8)(status << STENCIL_OFFSET);
}
private:
enum
{
COLOR_OFFSET = 0,
DEPTH_OFFSET = 2,
STENCIL_OFFSET = 4,
COLOR_MASK = (3<<COLOR_OFFSET),
DEPTH_MASK = (3<<DEPTH_OFFSET),
STENCIL_MASK = (3<<STENCIL_OFFSET),
};
deUint8 m_status;
};
void checkDepthRenderQuad (const ConstPixelBufferAccess& result,
const IVec2& posA,
const IVec2& posB,
vector<PixelStatus>& status)
{
for (int y = posA.y(); y <= posB.y(); y++)
for (int x = posA.x(); x <= posB.x(); x++)
{
PixelStatus& pixelStatus = status[x + y * result.getWidth()];
if (pixelStatus.getDepthStatus() == PixelStatus::STATUS_UNDEFINED)
{
const Vec4 minUvs = computeUvs(posA, posB, IVec2(x-1, y-1));
const Vec4 maxUvs = computeUvs(posA, posB, IVec2(x+1, y+1));
const bool softCheck = std::abs(x - posA.x()) <= 1 || std::abs(x - posB.x()) <= 1
|| std::abs(y - posA.y()) <= 1 || std::abs(y - posB.y()) <= 1;
const float resDepth = result.getPixDepth(x, y);
if (resDepth >= minUvs.x() && resDepth <= maxUvs.x())
pixelStatus.setDepthStatus(PixelStatus::STATUS_OK);
else if (!softCheck)
pixelStatus.setDepthStatus(PixelStatus::STATUS_FAIL);
}
}
}
void checkStencilRenderQuad (const ConstPixelBufferAccess& result,
const IVec2& posA,
const IVec2& posB,
vector<PixelStatus>& status)
{
for (int y = posA.y(); y <= posB.y(); y++)
for (int x = posA.x(); x <= posB.x(); x++)
{
PixelStatus& pixelStatus = status[x + y * result.getWidth()];
if (pixelStatus.getStencilStatus() == PixelStatus::STATUS_UNDEFINED)
{
const bool softCheck = std::abs(x - posA.x()) <= 1 || std::abs(x - posB.x()) <= 1
|| std::abs(y - posA.y()) <= 1 || std::abs(y - posB.y()) <= 1;
if (result.getPixStencil(x, y) == STENCIL_VALUE)
pixelStatus.setStencilStatus(PixelStatus::STATUS_OK);
else if (!softCheck)
pixelStatus.setStencilStatus(PixelStatus::STATUS_FAIL);
}
}
}
void checkColorRenderQuad (const ConstPixelBufferAccess& result,
const IVec2& posA,
const IVec2& posB,
vector<PixelStatus>& status)
{
const tcu::TextureFormat& format = result.getFormat();
const bool srgb = tcu::isSRGB(format);
const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(format.type);
const tcu::TextureFormatInfo textureInfo = tcu::getTextureFormatInfo(format);
const float clampMin = (float)(-MAX_INTEGER_VALUE);
const float clampMax = (float)(MAX_INTEGER_VALUE);
const Vec4 valueMax (de::clamp(textureInfo.valueMax[0], clampMin, clampMax),
de::clamp(textureInfo.valueMax[1], clampMin, clampMax),
de::clamp(textureInfo.valueMax[2], clampMin, clampMax),
de::clamp(textureInfo.valueMax[3], clampMin, clampMax));
const Vec4 valueMin (de::clamp(textureInfo.valueMin[0], clampMin, clampMax),
de::clamp(textureInfo.valueMin[1], clampMin, clampMax),
de::clamp(textureInfo.valueMin[2], clampMin, clampMax),
de::clamp(textureInfo.valueMin[3], clampMin, clampMax));
const BVec4 channelMask = tcu::getTextureFormatChannelMask(format);
IVec4 formatBitDepths = tcu::getTextureFormatBitDepth(format);
Vec4 threshold = Vec4(1.0f) / Vec4((float)(1 << formatBitDepths.x()),
(float)(1 << formatBitDepths.y()),
(float)(1 << formatBitDepths.z()),
(float)(1 << formatBitDepths.w()));
switch (channelClass)
{
case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
{
for (int y = posA.y(); y <= posB.y(); y++)
for (int x = posA.x(); x <= posB.x(); x++)
{
PixelStatus& pixelStatus = status[x + y * result.getWidth()];
if (pixelStatus.getColorStatus() == PixelStatus::STATUS_UNDEFINED)
{
const Vec4 minDiff = Vec4(1.0f) / (IVec4(1) << tcu::getTextureFormatMantissaBitDepth(format)).cast<float>();
const Vec4 minUvs = computeUvs(posA, posB, IVec2(x-1, y-1));
const Vec4 maxUvs = computeUvs(posA, posB, IVec2(x+1, y+1));
const bool softCheck = std::abs(x - posA.x()) <= 1 || std::abs(x - posB.x()) <= 1
|| std::abs(y - posA.y()) <= 1 || std::abs(y - posB.y()) <= 1;
const Vec4 resColor (result.getPixel(x, y));
Vec4 minRefColor = srgb ? tcu::linearToSRGB(valueMax * minUvs + valueMin * (Vec4(1.0f) - minUvs))
: valueMax * minUvs + valueMin * (Vec4(1.0f) - minUvs) - threshold;
Vec4 maxRefColor = srgb ? tcu::linearToSRGB(valueMax * maxUvs + valueMin * (Vec4(1.0f) - maxUvs))
: valueMax * maxUvs + valueMin * (Vec4(1.0f) - maxUvs) + threshold;
// Take into account rounding and quantization
if (channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT)
{
minRefColor = tcu::min(minRefColor * (Vec4(1.0f) - minDiff), minRefColor * (Vec4(1.0f) + minDiff));
maxRefColor = tcu::max(maxRefColor * (Vec4(1.0f) - minDiff), maxRefColor * (Vec4(1.0f) + minDiff));
}
else
{
minRefColor = minRefColor - minDiff;
maxRefColor = maxRefColor + minDiff;
}
DE_ASSERT(minRefColor[0] <= maxRefColor[0]);
DE_ASSERT(minRefColor[1] <= maxRefColor[1]);
DE_ASSERT(minRefColor[2] <= maxRefColor[2]);
DE_ASSERT(minRefColor[3] <= maxRefColor[3]);
if (tcu::anyNotEqual(tcu::logicalAnd(
tcu::logicalAnd(greaterThanEqual(resColor, minRefColor),
lessThanEqual(resColor, maxRefColor)),
channelMask), channelMask))
{
if (!softCheck)
pixelStatus.setColorStatus(PixelStatus::STATUS_FAIL);
}
else
pixelStatus.setColorStatus(PixelStatus::STATUS_OK);
}
}
break;
}
case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
{
for (int y = posA.y(); y <= posB.y(); y++)
for (int x = posA.x(); x <= posB.x(); x++)
{
PixelStatus& pixelStatus = status[x + y * result.getWidth()];
if (pixelStatus.getColorStatus() == PixelStatus::STATUS_UNDEFINED)
{
const Vec4 minUvs = computeUvs(posA, posB, IVec2(x-1, y-1));
const Vec4 maxUvs = computeUvs(posA, posB, IVec2(x+1, y+1));
const bool softCheck = std::abs(x - posA.x()) <= 1 || std::abs(x - posB.x()) <= 1
|| std::abs(y - posA.y()) <= 1 || std::abs(y - posB.y()) <= 1;
const UVec4 resColor (result.getPixelUint(x, y));
const Vec4 minRefColorF = valueMax * minUvs + valueMin * (Vec4(1.0f) - minUvs);
const Vec4 maxRefColorF = valueMax * maxUvs + valueMin * (Vec4(1.0f) - maxUvs);
const UVec4 minRefColor (minRefColorF.asUint());
const UVec4 maxRefColor (maxRefColorF.asUint());
DE_ASSERT(minRefColor[0] <= maxRefColor[0]);
DE_ASSERT(minRefColor[1] <= maxRefColor[1]);
DE_ASSERT(minRefColor[2] <= maxRefColor[2]);
DE_ASSERT(minRefColor[3] <= maxRefColor[3]);
if (tcu::anyNotEqual(tcu::logicalAnd(
tcu::logicalAnd(greaterThanEqual(resColor, minRefColor),
lessThanEqual(resColor, maxRefColor)),
channelMask), channelMask))
{
if (!softCheck)
pixelStatus.setColorStatus(PixelStatus::STATUS_FAIL);
}
else
pixelStatus.setColorStatus(PixelStatus::STATUS_OK);
}
}
break;
}
case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
{
for (int y = posA.y(); y <= posB.y(); y++)
for (int x = posA.x(); x <= posB.x(); x++)
{
PixelStatus& pixelStatus = status[x + y * result.getWidth()];
if (pixelStatus.getColorStatus() == PixelStatus::STATUS_UNDEFINED)
{
const Vec4 minUvs = computeUvs(posA, posB, IVec2(x-1, y-1));
const Vec4 maxUvs = computeUvs(posA, posB, IVec2(x+1, y+1));
const bool softCheck = std::abs(x - posA.x()) <= 1 || std::abs(x - posB.x()) <= 1
|| std::abs(y - posA.y()) <= 1 || std::abs(y - posB.y()) <= 1;
const IVec4 resColor (result.getPixelInt(x, y));
const Vec4 minRefColorF = valueMax * minUvs + valueMin * (Vec4(1.0f) - minUvs);
const Vec4 maxRefColorF = valueMax * maxUvs + valueMin * (Vec4(1.0f) - maxUvs);
const IVec4 minRefColor (minRefColorF.asInt());
const IVec4 maxRefColor (maxRefColorF.asInt());
DE_ASSERT(minRefColor[0] <= maxRefColor[0]);
DE_ASSERT(minRefColor[1] <= maxRefColor[1]);
DE_ASSERT(minRefColor[2] <= maxRefColor[2]);
DE_ASSERT(minRefColor[3] <= maxRefColor[3]);
if (tcu::anyNotEqual(tcu::logicalAnd(
tcu::logicalAnd(greaterThanEqual(resColor, minRefColor),
lessThanEqual(resColor, maxRefColor)),
channelMask), channelMask))
{
if (!softCheck)
pixelStatus.setColorStatus(PixelStatus::STATUS_FAIL);
}
else
pixelStatus.setColorStatus(PixelStatus::STATUS_OK);
}
}
break;
}
default:
DE_FATAL("Invalid channel class");
}
}
void checkColorClear (const ConstPixelBufferAccess& result,
const UVec2& offset,
const UVec2& size,
vector<PixelStatus>& status,
const VkClearColorValue& color)
{
DE_ASSERT(offset.x() + size.x() <= (deUint32)result.getWidth());
DE_ASSERT(offset.y() + size.y() <= (deUint32)result.getHeight());
DE_ASSERT(result.getWidth() * result.getHeight() == (int)status.size());
for (int y = offset.y(); y < (int)(offset.y() + size.y()); y++)
for (int x = offset.x(); x < (int)(offset.x() + size.x()); x++)
{
PixelStatus& pixelStatus = status[x + y * result.getWidth()];
DE_ASSERT(x + y * result.getWidth() < (int)status.size());
if (pixelStatus.getColorStatus() == PixelStatus::STATUS_UNDEFINED)
{
if (comparePixelToColorClearValue(result, x, y, color))
pixelStatus.setColorStatus(PixelStatus::STATUS_OK);
else
pixelStatus.setColorStatus(PixelStatus::STATUS_FAIL);
}
}
}
void checkDepthClear (const ConstPixelBufferAccess& result,
const UVec2& offset,
const UVec2& size,
vector<PixelStatus>& status,
float depth)
{
for (int y = offset.y(); y < (int)(offset.y() + size.y()); y++)
for (int x = offset.x(); x < (int)(offset.x() + size.x()); x++)
{
PixelStatus& pixelStatus = status[x + y * result.getWidth()];
if (pixelStatus.getDepthStatus() == PixelStatus::STATUS_UNDEFINED)
{
if (comparePixelToDepthClearValue(result, x, y, depth))
pixelStatus.setDepthStatus(PixelStatus::STATUS_OK);
else
pixelStatus.setDepthStatus(PixelStatus::STATUS_FAIL);
}
}
}
void checkStencilClear (const ConstPixelBufferAccess& result,
const UVec2& offset,
const UVec2& size,
vector<PixelStatus>& status,
deUint32 stencil)
{
for (int y = offset.y(); y < (int)(offset.y() + size.y()); y++)
for (int x = offset.x(); x < (int)(offset.x() + size.x()); x++)
{
PixelStatus& pixelStatus = status[x + y * result.getWidth()];
if (pixelStatus.getStencilStatus() == PixelStatus::STATUS_UNDEFINED)
{
if (comparePixelToStencilClearValue(result, x, y, stencil))
pixelStatus.setStencilStatus(PixelStatus::STATUS_OK);
else
pixelStatus.setStencilStatus(PixelStatus::STATUS_FAIL);
}
}
}
bool verifyAttachment (const ConstPixelBufferAccess& result,
const Maybe<ConstPixelBufferAccess>& secondaryResult,
const RenderPass& renderPassInfo,
const Maybe<VkClearValue>& renderPassClearValue,
const Maybe<VkClearValue>& imageClearValue,
const vector<Subpass>& subpasses,
const vector<SubpassRenderInfo>& subpassRenderInfo,
const PixelBufferAccess& errorImage,
deUint32 attachmentIndex,
const UVec2& renderPos,
const UVec2& renderSize)
{
const tcu::TextureFormat& format = result.getFormat();
const bool hasDepth = tcu::hasDepthComponent(format.order);
const bool hasStencil = tcu::hasStencilComponent(format.order);
const bool isColorFormat = !hasDepth && !hasStencil;
const PixelStatus initialStatus (isColorFormat ? PixelStatus::STATUS_UNDEFINED : PixelStatus::STATUS_OK,
hasDepth ? PixelStatus::STATUS_UNDEFINED : PixelStatus::STATUS_OK,
hasStencil ? PixelStatus::STATUS_UNDEFINED : PixelStatus::STATUS_OK);
bool attachmentIsUsed = false;
vector<PixelStatus> status (result.getWidth() * result.getHeight(), initialStatus);
tcu::clear(errorImage, Vec4(0.0f, 1.0f, 0.0f, 1.0f));
// Check if attachment is used
for (int subpassNdx = 0; subpassNdx < (int)subpasses.size(); subpassNdx++)
{
const Subpass& subpass = subpasses[subpassNdx];
const Maybe<deUint32> attachmentNdx = findColorAttachment(subpass, attachmentIndex);
if (attachmentNdx || subpass.getDepthStencilAttachment().getAttachment() == attachmentIndex)
attachmentIsUsed = true;
}
// Set all pixels that have undefined values to OK
if (attachmentIsUsed && (((isColorFormat || hasDepth) && renderPassInfo.getAttachments()[attachmentIndex].getStoreOp() == VK_ATTACHMENT_STORE_OP_DONT_CARE)
|| (hasStencil && renderPassInfo.getAttachments()[attachmentIndex].getStencilStoreOp() == VK_ATTACHMENT_STORE_OP_DONT_CARE)))
{
for(int y = renderPos.y(); y < (int)(renderPos.y() + renderSize.y()); y++)
for(int x = renderPos.x(); x < (int)(renderPos.x() + renderSize.x()); x++)
{
PixelStatus& pixelStatus = status[x + y * result.getWidth()];
if (isColorFormat && renderPassInfo.getAttachments()[attachmentIndex].getStoreOp() == VK_ATTACHMENT_STORE_OP_DONT_CARE)
pixelStatus.setColorStatus(PixelStatus::STATUS_OK);
else
{
if (hasDepth && renderPassInfo.getAttachments()[attachmentIndex].getStoreOp() == VK_ATTACHMENT_STORE_OP_DONT_CARE)
pixelStatus.setDepthStatus(PixelStatus::STATUS_OK);
if (hasStencil && renderPassInfo.getAttachments()[attachmentIndex].getStencilStoreOp() == VK_ATTACHMENT_STORE_OP_DONT_CARE)
pixelStatus.setStencilStatus(PixelStatus::STATUS_OK);
}
}
}
// Check renderpass rendering results
if (renderPassInfo.getAttachments()[attachmentIndex].getStoreOp() == VK_ATTACHMENT_STORE_OP_STORE
|| (hasStencil && renderPassInfo.getAttachments()[attachmentIndex].getStencilStoreOp() == VK_ATTACHMENT_STORE_OP_STORE))
{
// Check subpass rendering results
for (int subpassNdx = (int)subpasses.size() - 1; subpassNdx >= 0; subpassNdx--)
{
const Subpass& subpass = subpasses[subpassNdx];
const SubpassRenderInfo& renderInfo = subpassRenderInfo[subpassNdx];
const Maybe<deUint32> attachmentNdx = findColorAttachment(subpass, attachmentIndex);
// Check rendered quad
if (renderInfo.getRenderQuad() && (attachmentNdx || subpass.getDepthStencilAttachment().getAttachment() == attachmentIndex))
{
const RenderQuad& renderQuad = *renderInfo.getRenderQuad();
const Vec4 posA = renderQuad.getCornerA();
const Vec4 posB = renderQuad.getCornerB();
const Vec2 origin = Vec2((float)renderInfo.getViewportOffset().x(), (float)renderInfo.getViewportOffset().y()) + Vec2((float)renderInfo.getViewportSize().x(), (float)renderInfo.getViewportSize().y()) / Vec2(2.0f);
const Vec2 p = Vec2((float)renderInfo.getViewportSize().x(), (float)renderInfo.getViewportSize().y()) / Vec2(2.0f);
const IVec2 posAI ((deInt32)(origin.x() + (p.x() * posA.x())),
(deInt32)(origin.y() + (p.y() * posA.y())));
const IVec2 posBI ((deInt32)(origin.x() + (p.x() * posB.x())),
(deInt32)(origin.y() + (p.y() * posB.y())));
if (isColorFormat)
checkColorRenderQuad(result, posAI, posBI, status);
else
{
if (hasDepth)
checkDepthRenderQuad(result, posAI, posBI, status);
if (hasDepth && hasStencil)
checkStencilRenderQuad(*secondaryResult, posAI, posBI, status);
else if (hasStencil)
checkStencilRenderQuad(result, posAI, posBI, status);
}
}
// Check color attachment clears
if (attachmentNdx && !renderInfo.getColorClears().empty())
{
const ColorClear& clear = renderInfo.getColorClears()[*attachmentNdx];
checkColorClear(result, clear.getOffset(), clear.getSize(), status, clear.getColor());
}
// Check depth/stencil attachment clears
if (subpass.getDepthStencilAttachment().getAttachment() == attachmentIndex && renderInfo.getDepthStencilClear())
{
const DepthStencilClear clear = *renderInfo.getDepthStencilClear();
if (hasDepth)
checkDepthClear(result, clear.getOffset(), clear.getSize(), status, clear.getDepth());
if (hasDepth && hasStencil)
checkStencilClear(*secondaryResult, clear.getOffset(), clear.getSize(), status, clear.getStencil());
else if (hasStencil)
checkStencilClear(result, clear.getOffset(), clear.getSize(), status, clear.getStencil());
}
}
// Check renderpas clear results
if (attachmentIsUsed && renderPassClearValue)
{
if (isColorFormat)
{
if (renderPassInfo.getAttachments()[attachmentIndex].getLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR)
checkColorClear(result, renderPos, renderSize, status, renderPassClearValue->color);
}
else
{
if (hasDepth && renderPassInfo.getAttachments()[attachmentIndex].getLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR)
checkDepthClear(result, renderPos, renderSize, status, renderPassClearValue->depthStencil.depth);
if (hasDepth && hasStencil && renderPassInfo.getAttachments()[attachmentIndex].getStencilLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR)
checkStencilClear(*secondaryResult, renderPos, renderSize, status, renderPassClearValue->depthStencil.stencil);
else if (hasStencil && renderPassInfo.getAttachments()[attachmentIndex].getStencilLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR)
checkStencilClear(result, renderPos, renderSize, status, renderPassClearValue->depthStencil.stencil);
}
}
}
// Set all pixels that have undefined values fater renderpass to OK
if (attachmentIsUsed && (((isColorFormat || hasDepth) && renderPassInfo.getAttachments()[attachmentIndex].getLoadOp() == VK_ATTACHMENT_LOAD_OP_DONT_CARE)
|| (hasStencil && renderPassInfo.getAttachments()[attachmentIndex].getStencilLoadOp() == VK_ATTACHMENT_LOAD_OP_DONT_CARE)))
{
for(int y = renderPos.y(); y < (int)(renderPos.y() + renderSize.y()); y++)
for(int x = renderPos.x(); x < (int)(renderPos.x() + renderSize.x()); x++)
{
PixelStatus& pixelStatus = status[x + y * result.getWidth()];
if (pixelStatus.getColorStatus() == PixelStatus::STATUS_UNDEFINED
&& isColorFormat && renderPassInfo.getAttachments()[attachmentIndex].getLoadOp() == VK_ATTACHMENT_LOAD_OP_DONT_CARE)
pixelStatus.setColorStatus(PixelStatus::STATUS_OK);
else
{
if (pixelStatus.getDepthStatus() == PixelStatus::STATUS_UNDEFINED
&& hasDepth && renderPassInfo.getAttachments()[attachmentIndex].getLoadOp() == VK_ATTACHMENT_LOAD_OP_DONT_CARE)
pixelStatus.setDepthStatus(PixelStatus::STATUS_OK);
if (pixelStatus.getStencilStatus() == PixelStatus::STATUS_UNDEFINED
&& hasStencil && renderPassInfo.getAttachments()[attachmentIndex].getStencilLoadOp() == VK_ATTACHMENT_LOAD_OP_DONT_CARE)
pixelStatus.setStencilStatus(PixelStatus::STATUS_OK);
}
}
}
if (imageClearValue)
{
if (isColorFormat)
checkColorClear(result, UVec2(0, 0), UVec2(result.getWidth(), result.getHeight()), status, imageClearValue->color);
else
{
if (hasDepth)
checkDepthClear(result, UVec2(0, 0), UVec2(result.getWidth(), result.getHeight()), status, imageClearValue->depthStencil.depth);
if (hasDepth && hasStencil)
checkStencilClear(*secondaryResult, UVec2(0, 0), UVec2(secondaryResult->getWidth(), result.getHeight()), status, imageClearValue->depthStencil.stencil);
else if (hasStencil)
checkStencilClear(result, UVec2(0, 0), UVec2(result.getWidth(), result.getHeight()), status, imageClearValue->depthStencil.stencil);
}
}
{
bool isOk = true;
for(int y = 0; y < result.getHeight(); y++)
for(int x = 0; x < result.getWidth(); x++)
{
const PixelStatus& pixelStatus = status[x + y * result.getWidth()];
if (isColorFormat)
{
if (pixelStatus.getColorStatus() != PixelStatus::STATUS_OK)
{
if (pixelStatus.getColorStatus() == PixelStatus::STATUS_UNDEFINED)
errorImage.setPixel(Vec4(1.0f, 1.0f, 0.0f, 1.0f), x, y);
else if (pixelStatus.getColorStatus() == PixelStatus::STATUS_FAIL)
errorImage.setPixel(Vec4(1.0f, 0.0f, 0.0f, 1.0f), x, y);
isOk = false;
}
}
else
{
if (hasDepth && pixelStatus.getDepthStatus() != PixelStatus::STATUS_OK)
{
errorImage.setPixel(Vec4(1.0f, 0.0f, 0.0f, 1.0f), x, y);
isOk = false;
}
if (hasStencil && pixelStatus.getStencilStatus() != PixelStatus::STATUS_OK)
{
errorImage.setPixel(Vec4(1.0f, 0.0f, 0.0f, 1.0f), x, y);
isOk = false;
}
}
}
return isOk;
}
}
bool logAndVerifyImages (TestLog& log,
const DeviceInterface& vk,
VkDevice device,
const vector<de::SharedPtr<AttachmentResources> >& attachmentResources,
const vector<bool>& attachmentIsLazy,
const RenderPass& renderPassInfo,
const vector<Maybe<VkClearValue> >& renderPassClearValues,
const vector<Maybe<VkClearValue> >& imageClearValues,
const vector<SubpassRenderInfo>& subpassRenderInfo,
const UVec2& targetSize,
const TestConfig& config)
{
vector<tcu::TextureLevel> referenceAttachments;
bool isOk = true;
log << TestLog::Message << "Reference images fill undefined pixels with grid pattern." << TestLog::EndMessage;
renderReferenceImages(referenceAttachments, renderPassInfo, targetSize, imageClearValues, renderPassClearValues, subpassRenderInfo, config.renderPos, config.renderSize);
for (size_t attachmentNdx = 0; attachmentNdx < renderPassInfo.getAttachments().size(); attachmentNdx++)
{
if (!attachmentIsLazy[attachmentNdx])
{
const Attachment attachment = renderPassInfo.getAttachments()[attachmentNdx];
const tcu::TextureFormat format = mapVkFormat(attachment.getFormat());
if (tcu::hasDepthComponent(format.order) && tcu::hasStencilComponent(format.order))
{
const tcu::TextureFormat depthFormat = getDepthCopyFormat(attachment.getFormat());
const VkDeviceSize depthBufferSize = targetSize.x() * targetSize.y() * depthFormat.getPixelSize();
void* const depthPtr = attachmentResources[attachmentNdx]->getResultMemory().getHostPtr();
const tcu::TextureFormat stencilFormat = getStencilCopyFormat(attachment.getFormat());
const VkDeviceSize stencilBufferSize = targetSize.x() * targetSize.y() * stencilFormat.getPixelSize();
void* const stencilPtr = attachmentResources[attachmentNdx]->getSecondaryResultMemory().getHostPtr();
const VkMappedMemoryRange ranges[] =
{
{
VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, // sType;
DE_NULL, // pNext;
attachmentResources[attachmentNdx]->getResultMemory().getMemory(), // mem;
attachmentResources[attachmentNdx]->getResultMemory().getOffset(), // offset;
depthBufferSize // size;
},
{
VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, // sType;
DE_NULL, // pNext;
attachmentResources[attachmentNdx]->getSecondaryResultMemory().getMemory(), // mem;
attachmentResources[attachmentNdx]->getSecondaryResultMemory().getOffset(), // offset;
stencilBufferSize // size;
}
};
VK_CHECK(vk.invalidateMappedMemoryRanges(device, 2u, ranges));
{
const ConstPixelBufferAccess depthAccess (depthFormat, targetSize.x(), targetSize.y(), 1, depthPtr);
const ConstPixelBufferAccess stencilAccess (stencilFormat, targetSize.x(), targetSize.y(), 1, stencilPtr);
tcu::TextureLevel errorImage (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), targetSize.x(), targetSize.y());
log << TestLog::Image("Attachment" + de::toString(attachmentNdx) + "Depth", "Attachment " + de::toString(attachmentNdx) + " Depth", depthAccess);
log << TestLog::Image("Attachment" + de::toString(attachmentNdx) + "Stencil", "Attachment " + de::toString(attachmentNdx) + " Stencil", stencilAccess);
log << TestLog::Image("AttachmentReference" + de::toString(attachmentNdx), "Attachment reference " + de::toString(attachmentNdx), referenceAttachments[attachmentNdx].getAccess());
if ((renderPassInfo.getAttachments()[attachmentNdx].getStoreOp() == VK_ATTACHMENT_STORE_OP_STORE || renderPassInfo.getAttachments()[attachmentNdx].getStencilStoreOp() == VK_ATTACHMENT_STORE_OP_STORE)
&& !verifyAttachment(depthAccess, tcu::just(stencilAccess), renderPassInfo, renderPassClearValues[attachmentNdx], imageClearValues[attachmentNdx], renderPassInfo.getSubpasses(), subpassRenderInfo, errorImage.getAccess(), (deUint32)attachmentNdx, config.renderPos, config.renderSize))
{
log << TestLog::Image("AttachmentError" + de::toString(attachmentNdx), "Attachment Error " + de::toString(attachmentNdx), errorImage.getAccess());
isOk = false;
}
}
}
else
{
const VkDeviceSize bufferSize = targetSize.x() * targetSize.y() * format.getPixelSize();
void* const ptr = attachmentResources[attachmentNdx]->getResultMemory().getHostPtr();
const VkMappedMemoryRange range =
{
VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, // sType;
DE_NULL, // pNext;
attachmentResources[attachmentNdx]->getResultMemory().getMemory(), // mem;
attachmentResources[attachmentNdx]->getResultMemory().getOffset(), // offset;
bufferSize // size;
};
VK_CHECK(vk.invalidateMappedMemoryRanges(device, 1u, &range));
{
const ConstPixelBufferAccess access (format, targetSize.x(), targetSize.y(), 1, ptr);
tcu::TextureLevel errorImage (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), targetSize.x(), targetSize.y());
log << TestLog::Image("Attachment" + de::toString(attachmentNdx), "Attachment " + de::toString(attachmentNdx), access);
log << TestLog::Image("AttachmentReference" + de::toString(attachmentNdx), "Attachment reference " + de::toString(attachmentNdx), referenceAttachments[attachmentNdx].getAccess());
if ((renderPassInfo.getAttachments()[attachmentNdx].getStoreOp() == VK_ATTACHMENT_STORE_OP_STORE || renderPassInfo.getAttachments()[attachmentNdx].getStencilStoreOp() == VK_ATTACHMENT_STORE_OP_STORE)
&& !verifyAttachment(access, tcu::nothing<ConstPixelBufferAccess>(), renderPassInfo, renderPassClearValues[attachmentNdx], imageClearValues[attachmentNdx], renderPassInfo.getSubpasses(), subpassRenderInfo, errorImage.getAccess(), (deUint32)attachmentNdx, config.renderPos, config.renderSize))
{
log << TestLog::Image("AttachmentError" + de::toString(attachmentNdx), "Attachment Error " + de::toString(attachmentNdx), errorImage.getAccess());
isOk = false;
}
}
}
}
}
return isOk;
}
std::string getAttachmentType (VkFormat vkFormat)
{
const tcu::TextureFormat format = mapVkFormat(vkFormat);
const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(format.type);
switch (channelClass)
{
case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
return "ivec4";
case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
return "uvec4";
case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
return "vec4";
default:
DE_FATAL("Unknown channel class");
return "";
}
}
void createTestShaders (SourceCollections& dst, TestConfig config)
{
if (config.renderTypes & TestConfig::RENDERTYPES_DRAW)
{
const vector<Subpass>& subpasses = config.renderPass.getSubpasses();
for (size_t subpassNdx = 0; subpassNdx < subpasses.size(); subpassNdx++)
{
const Subpass& subpass = subpasses[subpassNdx];
std::ostringstream vertexShader;
std::ostringstream fragmentShader;
vertexShader << "#version 310 es\n"
<< "layout(location = 0) in highp vec4 a_position;\n"
<< "layout(location = 0) out highp vec2 v_color;\n"
<< "void main (void) {\n"
<< "\thighp float a = 0.5 + a_position.x;\n"
<< "\thighp float b = 0.5 + a_position.y;\n"
<< "\tv_color = vec2(a, b);\n"
<< "\tgl_Position = a_position;\n"
<< "}\n";
fragmentShader << "#version 310 es\n"
<< "layout(location = 0) in highp vec2 v_color;\n";
for (size_t attachmentNdx = 0; attachmentNdx < subpass.getColorAttachments().size(); attachmentNdx++)
{
const std::string attachmentType = getAttachmentType(config.renderPass.getAttachments()[subpass.getColorAttachments()[attachmentNdx].getAttachment()].getFormat());
fragmentShader << "layout(location = " << attachmentNdx << ") out highp " << attachmentType << " o_color" << attachmentNdx << ";\n";
}
fragmentShader << "void main (void) {\n"
<< "\thighp vec4 scale = vec4(v_color.x, v_color.y, v_color.x * v_color.y, (v_color.x + v_color.y) / 2.0);\n";
for (size_t attachmentNdx = 0; attachmentNdx < subpass.getColorAttachments().size(); attachmentNdx++)
{
const tcu::TextureFormat format = mapVkFormat(config.renderPass.getAttachments()[subpass.getColorAttachments()[attachmentNdx].getAttachment()].getFormat());
const tcu::TextureFormatInfo formatInfo = tcu::getTextureFormatInfo(format);
const float clampMin = (float)(-MAX_INTEGER_VALUE);
const float clampMax = (float)(MAX_INTEGER_VALUE);
const Vec4 valueMax (de::clamp(formatInfo.valueMax[0], clampMin, clampMax),
de::clamp(formatInfo.valueMax[1], clampMin, clampMax),
de::clamp(formatInfo.valueMax[2], clampMin, clampMax),
de::clamp(formatInfo.valueMax[3], clampMin, clampMax));
const Vec4 valueMin (de::clamp(formatInfo.valueMin[0], clampMin, clampMax),
de::clamp(formatInfo.valueMin[1], clampMin, clampMax),
de::clamp(formatInfo.valueMin[2], clampMin, clampMax),
de::clamp(formatInfo.valueMin[3], clampMin, clampMax));
const std::string attachmentType = getAttachmentType(config.renderPass.getAttachments()[subpass.getColorAttachments()[attachmentNdx].getAttachment()].getFormat());
fragmentShader << "\to_color" << attachmentNdx << " = " << attachmentType << "(vec4" << valueMin << " + vec4" << (valueMax - valueMin) << " * scale);\n";
}
fragmentShader << "}\n";
dst.glslSources.add(de::toString(subpassNdx) + "-vert") << glu::VertexSource(vertexShader.str());
dst.glslSources.add(de::toString(subpassNdx) + "-frag") << glu::FragmentSource(fragmentShader.str());
}
}
}
void initializeAttachmentIsLazy (vector<bool>& attachmentIsLazy, const vector<Attachment>& attachments, TestConfig::ImageMemory imageMemory)
{
bool lastAttachmentWasLazy = false;
for (size_t attachmentNdx = 0; attachmentNdx < attachments.size(); attachmentNdx++)
{
if (attachments[attachmentNdx].getLoadOp() != VK_ATTACHMENT_LOAD_OP_LOAD
&& attachments[attachmentNdx].getStoreOp() != VK_ATTACHMENT_STORE_OP_STORE
&& attachments[attachmentNdx].getStencilLoadOp() != VK_ATTACHMENT_LOAD_OP_LOAD
&& attachments[attachmentNdx].getStencilStoreOp() != VK_ATTACHMENT_STORE_OP_STORE)
{
if (imageMemory == TestConfig::IMAGEMEMORY_LAZY || (imageMemory & TestConfig::IMAGEMEMORY_LAZY && !lastAttachmentWasLazy))
{
attachmentIsLazy.push_back(true);
lastAttachmentWasLazy = true;
}
else if (imageMemory & TestConfig::IMAGEMEMORY_STRICT)
{
attachmentIsLazy.push_back(false);
lastAttachmentWasLazy = false;
}
else
DE_FATAL("Unknown imageMemory");
}
else
attachmentIsLazy.push_back(false);
}
}
enum AttachmentRefType
{
ATTACHMENTREFTYPE_COLOR,
ATTACHMENTREFTYPE_DEPTH_STENCIL,
ATTACHMENTREFTYPE_INPUT,
ATTACHMENTREFTYPE_RESOLVE,
};
VkImageUsageFlags getImageUsageFromLayout(VkImageLayout layout)
{
switch (layout)
{
case VK_IMAGE_LAYOUT_GENERAL:
case VK_IMAGE_LAYOUT_PREINITIALIZED:
return 0;
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
return VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
return VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
return VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
return VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
return VK_IMAGE_USAGE_TRANSFER_DST_BIT;
default:
DE_FATAL("Unexpected image layout");
return 0;
}
}
void getImageUsageFromAttachmentReferences(vector<VkImageUsageFlags>& attachmentImageUsage, AttachmentRefType refType, size_t count, const AttachmentReference* references)
{
for (size_t referenceNdx = 0; referenceNdx < count; ++referenceNdx)
{
const deUint32 attachment = references[referenceNdx].getAttachment();
if (attachment != VK_ATTACHMENT_UNUSED)
{
VkImageUsageFlags usage;
switch (refType)
{
case ATTACHMENTREFTYPE_COLOR:
case ATTACHMENTREFTYPE_RESOLVE:
usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
break;
case ATTACHMENTREFTYPE_DEPTH_STENCIL:
usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
break;
case ATTACHMENTREFTYPE_INPUT:
usage = VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
break;
default:
DE_FATAL("Unexpected attachment reference type");
usage = 0;
break;
}
attachmentImageUsage[attachment] |= usage;
}
}
}
void getImageUsageFromAttachmentReferences(vector<VkImageUsageFlags>& attachmentImageUsage, AttachmentRefType refType, const vector<AttachmentReference>& references)
{
if (!references.empty())
{
getImageUsageFromAttachmentReferences(attachmentImageUsage, refType, references.size(), &references[0]);
}
}
void initializeAttachmentImageUsage (Context &context, vector<VkImageUsageFlags>& attachmentImageUsage, const RenderPass& renderPassInfo, const vector<bool>& attachmentIsLazy, const vector<Maybe<VkClearValue> >& clearValues)
{
attachmentImageUsage.resize(renderPassInfo.getAttachments().size(), VkImageUsageFlags(0));
for (size_t subpassNdx = 0; subpassNdx < renderPassInfo.getSubpasses().size(); ++subpassNdx)
{
const Subpass& subpass = renderPassInfo.getSubpasses()[subpassNdx];
getImageUsageFromAttachmentReferences(attachmentImageUsage, ATTACHMENTREFTYPE_COLOR, subpass.getColorAttachments());
getImageUsageFromAttachmentReferences(attachmentImageUsage, ATTACHMENTREFTYPE_DEPTH_STENCIL, 1, &subpass.getDepthStencilAttachment());
getImageUsageFromAttachmentReferences(attachmentImageUsage, ATTACHMENTREFTYPE_INPUT, subpass.getInputAttachments());
getImageUsageFromAttachmentReferences(attachmentImageUsage, ATTACHMENTREFTYPE_RESOLVE, subpass.getResolveAttachments());
}
for (size_t attachmentNdx = 0; attachmentNdx < renderPassInfo.getAttachments().size(); attachmentNdx++)
{
const Attachment& attachment = renderPassInfo.getAttachments()[attachmentNdx];
const VkFormatProperties formatProperties = getPhysicalDeviceFormatProperties(context.getInstanceInterface(), context.getPhysicalDevice(), attachment.getFormat());
const VkFormatFeatureFlags supportedFeatures = formatProperties.optimalTilingFeatures;
if ((supportedFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) != 0)
attachmentImageUsage[attachmentNdx] |= VK_IMAGE_USAGE_SAMPLED_BIT;
if ((supportedFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) != 0)
attachmentImageUsage[attachmentNdx] |= VK_IMAGE_USAGE_STORAGE_BIT;
attachmentImageUsage[attachmentNdx] |= getImageUsageFromLayout(attachment.getInitialLayout());
attachmentImageUsage[attachmentNdx] |= getImageUsageFromLayout(attachment.getFinalLayout());
if (!attachmentIsLazy[attachmentNdx])
{
if (clearValues[attachmentNdx])
attachmentImageUsage[attachmentNdx] |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
attachmentImageUsage[attachmentNdx] |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
}
}
}
void initializeSubpassIsSecondary (vector<bool>& subpassIsSecondary, const vector<Subpass>& subpasses, TestConfig::CommandBufferTypes commandBuffer)
{
bool lastSubpassWasSecondary = false;
for (size_t subpassNdx = 0; subpassNdx < subpasses.size(); subpassNdx++)
{
if (commandBuffer == TestConfig::COMMANDBUFFERTYPES_SECONDARY || (commandBuffer & TestConfig::COMMANDBUFFERTYPES_SECONDARY && !lastSubpassWasSecondary))
{
subpassIsSecondary.push_back(true);
lastSubpassWasSecondary = true;
}
else if (commandBuffer & TestConfig::COMMANDBUFFERTYPES_INLINE)
{
subpassIsSecondary.push_back(false);
lastSubpassWasSecondary = false;
}
else
DE_FATAL("Unknown commandBuffer");
}
}
void initializeImageClearValues (de::Random& rng, vector<Maybe<VkClearValue> >& clearValues, const vector<Attachment>& attachments, const vector<bool>& isLazy)
{
for (size_t attachmentNdx = 0; attachmentNdx < attachments.size(); attachmentNdx++)
{
if (!isLazy[attachmentNdx])
clearValues.push_back(just(randomClearValue(attachments[attachmentNdx], rng)));
else
clearValues.push_back(nothing<VkClearValue>());
}
}
void initializeRenderPassClearValues (de::Random& rng, vector<Maybe<VkClearValue> >& clearValues, const vector<Attachment>& attachments)
{
for (size_t attachmentNdx = 0; attachmentNdx < attachments.size(); attachmentNdx++)
{
if (attachments[attachmentNdx].getLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR
|| attachments[attachmentNdx].getStencilLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR)
{
clearValues.push_back(just(randomClearValue(attachments[attachmentNdx], rng)));
}
else
clearValues.push_back(nothing<VkClearValue>());
}
}
void initializeSubpassClearValues (de::Random& rng, vector<vector<VkClearColorValue> >& clearValues, const RenderPass& renderPass)
{
clearValues.resize(renderPass.getSubpasses().size());
for (size_t subpassNdx = 0; subpassNdx < renderPass.getSubpasses().size(); subpassNdx++)
{
const Subpass& subpass = renderPass.getSubpasses()[subpassNdx];
const vector<AttachmentReference>& colorAttachments = subpass.getColorAttachments();
clearValues[subpassNdx].resize(colorAttachments.size());
for (size_t attachmentRefNdx = 0; attachmentRefNdx < colorAttachments.size(); attachmentRefNdx++)
{
const AttachmentReference& attachmentRef = colorAttachments[attachmentRefNdx];
const Attachment& attachment = renderPass.getAttachments()[attachmentRef.getAttachment()];
clearValues[subpassNdx][attachmentRefNdx] = randomColorClearValue(attachment, rng);
}
}
}
void logSubpassRenderInfo (TestLog& log,
const SubpassRenderInfo& info)
{
log << TestLog::Message << "Viewport, offset: " << info.getViewportOffset() << ", size: " << info.getViewportSize() << TestLog::EndMessage;
if (info.isSecondary())
log << TestLog::Message << "Subpass uses secondary command buffers" << TestLog::EndMessage;
else
log << TestLog::Message << "Subpass uses inlined commands" << TestLog::EndMessage;
for (deUint32 attachmentNdx = 0; attachmentNdx < info.getColorClears().size(); attachmentNdx++)
{
const ColorClear& colorClear = info.getColorClears()[attachmentNdx];
log << TestLog::Message << "Clearing color attachment " << attachmentNdx
<< ". Offset: " << colorClear.getOffset()
<< ", Size: " << colorClear.getSize()
<< ", Color: " << clearColorToString(info.getColorAttachment(attachmentNdx).getFormat(), colorClear.getColor()) << TestLog::EndMessage;
}
if (info.getDepthStencilClear())
{
const DepthStencilClear& depthStencilClear = *info.getDepthStencilClear();
log << TestLog::Message << "Clearing depth stencil attachment"
<< ". Offset: " << depthStencilClear.getOffset()
<< ", Size: " << depthStencilClear.getSize()
<< ", Depth: " << depthStencilClear.getDepth()
<< ", Stencil: " << depthStencilClear.getStencil() << TestLog::EndMessage;
}
if (info.getRenderQuad())
{
const RenderQuad& renderQuad = *info.getRenderQuad();
log << TestLog::Message << "Rendering gradient quad to " << renderQuad.getCornerA() << " -> " << renderQuad.getCornerB() << TestLog::EndMessage;
}
}
void logTestCaseInfo (TestLog& log,
const TestConfig& config,
const vector<bool>& attachmentIsLazy,
const vector<Maybe<VkClearValue> >& imageClearValues,
const vector<Maybe<VkClearValue> >& renderPassClearValues,
const vector<SubpassRenderInfo>& subpassRenderInfo)
{
const RenderPass& renderPass = config.renderPass;
logRenderPassInfo(log, renderPass);
DE_ASSERT(attachmentIsLazy.size() == renderPass.getAttachments().size());
DE_ASSERT(imageClearValues.size() == renderPass.getAttachments().size());
DE_ASSERT(renderPassClearValues.size() == renderPass.getAttachments().size());
log << TestLog::Message << "TargetSize: " << config.targetSize << TestLog::EndMessage;
log << TestLog::Message << "Render area, Offset: " << config.renderPos << ", Size: " << config.renderSize << TestLog::EndMessage;
for (size_t attachmentNdx = 0; attachmentNdx < attachmentIsLazy.size(); attachmentNdx++)
{
const tcu::ScopedLogSection section (log, "Attachment" + de::toString(attachmentNdx), "Attachment " + de::toString(attachmentNdx));
if (attachmentIsLazy[attachmentNdx])
log << TestLog::Message << "Is lazy." << TestLog::EndMessage;
if (imageClearValues[attachmentNdx])
log << TestLog::Message << "Image is cleared to " << clearValueToString(renderPass.getAttachments()[attachmentNdx].getFormat(), *imageClearValues[attachmentNdx]) << " before rendering." << TestLog::EndMessage;
if (renderPass.getAttachments()[attachmentNdx].getLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR && renderPassClearValues[attachmentNdx])
log << TestLog::Message << "Attachment is cleared to " << clearValueToString(renderPass.getAttachments()[attachmentNdx].getFormat(), *renderPassClearValues[attachmentNdx]) << " in the beginning of the render pass." << TestLog::EndMessage;
}
for (size_t subpassNdx = 0; subpassNdx < renderPass.getSubpasses().size(); subpassNdx++)
{
const tcu::ScopedLogSection section (log, "Subpass" + de::toString(subpassNdx), "Subpass " + de::toString(subpassNdx));
logSubpassRenderInfo(log, subpassRenderInfo[subpassNdx]);
}
}
void initializeSubpassRenderInfo (vector<SubpassRenderInfo>& renderInfos, de::Random& rng, const RenderPass& renderPass, const TestConfig& config)
{
const TestConfig::CommandBufferTypes commandBuffer = config.commandBufferTypes;
const vector<Subpass>& subpasses = renderPass.getSubpasses();
bool lastSubpassWasSecondary = false;
for (deUint32 subpassNdx = 0; subpassNdx < (deUint32)subpasses.size(); subpassNdx++)
{
const Subpass& subpass = subpasses[subpassNdx];
const bool subpassIsSecondary = commandBuffer == TestConfig::COMMANDBUFFERTYPES_SECONDARY
|| (commandBuffer & TestConfig::COMMANDBUFFERTYPES_SECONDARY && !lastSubpassWasSecondary) ? true : false;
const UVec2 viewportSize ((config.renderSize * UVec2(2)) / UVec2(3));
const UVec2 viewportOffset (config.renderPos.x() + (subpassNdx % 2) * (config.renderSize.x() / 3),
config.renderPos.y() + ((subpassNdx / 2) % 2) * (config.renderSize.y() / 3));
vector<ColorClear> colorClears;
Maybe<DepthStencilClear> depthStencilClear;
Maybe<RenderQuad> renderQuad;
lastSubpassWasSecondary = subpassIsSecondary;
if (config.renderTypes & TestConfig::RENDERTYPES_CLEAR)
{
const vector<AttachmentReference>& colorAttachments = subpass.getColorAttachments();
for (size_t attachmentRefNdx = 0; attachmentRefNdx < colorAttachments.size(); attachmentRefNdx++)
{
const AttachmentReference& attachmentRef = colorAttachments[attachmentRefNdx];
const Attachment& attachment = renderPass.getAttachments()[attachmentRef.getAttachment()];
const UVec2 size ((viewportSize * UVec2(2)) / UVec2(3));
const UVec2 offset (viewportOffset.x() + ((deUint32)attachmentRefNdx % 2u) * (viewportSize.x() / 3u),
viewportOffset.y() + (((deUint32)attachmentRefNdx / 2u) % 2u) * (viewportSize.y() / 3u));
const VkClearColorValue color = randomColorClearValue(attachment, rng);
colorClears.push_back(ColorClear(offset, size, color));
}
if (subpass.getDepthStencilAttachment().getAttachment() != VK_ATTACHMENT_UNUSED)
{
const Attachment& attachment = renderPass.getAttachments()[subpass.getDepthStencilAttachment().getAttachment()];
const UVec2 size ((viewportSize * UVec2(2)) / UVec2(3));
const UVec2 offset (viewportOffset.x() + ((deUint32)colorAttachments.size() % 2u) * (viewportSize.x() / 3u),
viewportOffset.y() + (((deUint32)colorAttachments.size() / 2u) % 2u) * (viewportSize.y() / 3u));
const VkClearValue value = randomClearValue(attachment, rng);
depthStencilClear = tcu::just(DepthStencilClear(offset, size, value.depthStencil.depth, value.depthStencil.stencil));
}
}
if (config.renderTypes & TestConfig::RENDERTYPES_DRAW)
{
// (-0.5,-0.5) - (0.5,0.5) rounded to pixel edges
const float x = (float)(viewportSize.x() / 4) / (float)(viewportSize.x() / 2);
const float y = (float)(viewportSize.y() / 4) / (float)(viewportSize.y() / 2);
renderQuad = tcu::just(RenderQuad(tcu::Vec4(-x, -y, 0.0f, 1.0f), tcu::Vec4(x, y, 1.0f, 1.0f)));
}
renderInfos.push_back(SubpassRenderInfo(renderPass, subpassNdx, subpassIsSecondary, viewportOffset, viewportSize, renderQuad, colorClears, depthStencilClear));
}
}
void checkTextureFormatSupport (TestLog& log,
const InstanceInterface& vk,
VkPhysicalDevice device,
const vector<Attachment>& attachments)
{
bool supported = true;
for (size_t attachmentNdx = 0; attachmentNdx < attachments.size(); attachmentNdx++)
{
const Attachment& attachment = attachments[attachmentNdx];
const tcu::TextureFormat format = mapVkFormat(attachment.getFormat());
const bool isDepthOrStencilAttachment = hasDepthComponent(format.order) || hasStencilComponent(format.order);
const VkFormatFeatureFlags flags = isDepthOrStencilAttachment? VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT : VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
VkFormatProperties properties;
vk.getPhysicalDeviceFormatProperties(device, attachment.getFormat(), &properties);
if ((properties.optimalTilingFeatures & flags) != flags)
{
supported = false;
log << TestLog::Message << "Format: " << attachment.getFormat() << " not supported as " << (isDepthOrStencilAttachment ? "depth stencil attachment" : "color attachment") << TestLog::EndMessage;
}
}
if (!supported)
TCU_THROW(NotSupportedError, "Format not supported");
}
tcu::TestStatus renderPassTest (Context& context, TestConfig config)
{
const UVec2 targetSize = config.targetSize;
const UVec2 renderPos = config.renderPos;
const UVec2 renderSize = config.renderSize;
const RenderPass& renderPassInfo = config.renderPass;
TestLog& log = context.getTestContext().getLog();
de::Random rng (config.seed);
vector<bool> attachmentIsLazy;
vector<VkImageUsageFlags> attachmentImageUsage;
vector<Maybe<VkClearValue> > imageClearValues;
vector<Maybe<VkClearValue> > renderPassClearValues;
vector<bool> subpassIsSecondary;
vector<SubpassRenderInfo> subpassRenderInfo;
vector<vector<VkClearColorValue> > subpassColorClearValues;
initializeAttachmentIsLazy(attachmentIsLazy, renderPassInfo.getAttachments(), config.imageMemory);
initializeImageClearValues(rng, imageClearValues, renderPassInfo.getAttachments(), attachmentIsLazy);
initializeAttachmentImageUsage(context, attachmentImageUsage, renderPassInfo, attachmentIsLazy, imageClearValues);
initializeRenderPassClearValues(rng, renderPassClearValues, renderPassInfo.getAttachments());
initializeSubpassIsSecondary(subpassIsSecondary, renderPassInfo.getSubpasses(), config.commandBufferTypes);
initializeSubpassClearValues(rng, subpassColorClearValues, renderPassInfo);
initializeSubpassRenderInfo(subpassRenderInfo, rng, renderPassInfo, config);
logTestCaseInfo(log, config, attachmentIsLazy, imageClearValues, renderPassClearValues, subpassRenderInfo);
checkTextureFormatSupport(log, context.getInstanceInterface(), context.getPhysicalDevice(), config.renderPass.getAttachments());
{
const vk::VkPhysicalDeviceProperties properties = vk::getPhysicalDeviceProperties(context.getInstanceInterface(), context.getPhysicalDevice());
log << TestLog::Message << "Max color attachments: " << properties.limits.maxColorAttachments << TestLog::EndMessage;
for (size_t subpassNdx = 0; subpassNdx < renderPassInfo.getSubpasses().size(); subpassNdx++)
{
if (renderPassInfo.getSubpasses()[subpassNdx].getColorAttachments().size() > (size_t)properties.limits.maxColorAttachments)
TCU_THROW(NotSupportedError, "Subpass uses more than maxColorAttachments.");
}
}
{
const VkDevice device = context.getDevice();
const DeviceInterface& vk = context.getDeviceInterface();
const VkQueue queue = context.getUniversalQueue();
const deUint32 queueIndex = context.getUniversalQueueFamilyIndex();
Allocator& allocator = context.getDefaultAllocator();
const Unique<VkRenderPass> renderPass (createRenderPass(vk, device, renderPassInfo));
const Unique<VkCommandPool> commandBufferPool (createCommandPool(vk, device, queueIndex, 0));
const Unique<VkCommandBuffer> initializeImagesCommandBuffer (allocateCommandBuffer(vk, device, *commandBufferPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
const Unique<VkCommandBuffer> renderCommandBuffer (allocateCommandBuffer(vk, device, *commandBufferPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
const Unique<VkCommandBuffer> readImagesToBuffersCommandBuffer (allocateCommandBuffer(vk, device, *commandBufferPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
vector<de::SharedPtr<AttachmentResources> > attachmentResources;
vector<de::SharedPtr<SubpassRenderer> > subpassRenderers;
vector<VkImageView> attachmentViews;
for (size_t attachmentNdx = 0; attachmentNdx < renderPassInfo.getAttachments().size(); attachmentNdx++)
{
const Attachment& attachmentInfo = renderPassInfo.getAttachments()[attachmentNdx];
attachmentResources.push_back(de::SharedPtr<AttachmentResources>(new AttachmentResources(vk, device, allocator, queueIndex, targetSize, attachmentInfo, attachmentImageUsage[attachmentNdx])));
attachmentViews.push_back(attachmentResources[attachmentNdx]->getAttachmentView());
}
beginCommandBuffer(vk, *initializeImagesCommandBuffer, (VkCommandBufferUsageFlags)0, DE_NULL, 0, DE_NULL, VK_FALSE, (VkQueryControlFlags)0, (VkQueryPipelineStatisticFlags)0);
pushImageInitializationCommands(vk, *initializeImagesCommandBuffer, renderPassInfo.getAttachments(), attachmentResources, queueIndex, imageClearValues);
endCommandBuffer(vk, *initializeImagesCommandBuffer);
{
const Unique<VkFramebuffer> framebuffer (createFramebuffer(vk, device, *renderPass, targetSize, attachmentViews));
for (size_t subpassNdx = 0; subpassNdx < renderPassInfo.getSubpasses().size(); subpassNdx++)
subpassRenderers.push_back(de::SharedPtr<SubpassRenderer>(new SubpassRenderer(context, vk, device, allocator, *renderPass, *framebuffer, *commandBufferPool, queueIndex, subpassRenderInfo[subpassNdx])));
beginCommandBuffer(vk, *renderCommandBuffer, (VkCommandBufferUsageFlags)0, DE_NULL, 0, DE_NULL, VK_FALSE, (VkQueryControlFlags)0, (VkQueryPipelineStatisticFlags)0);
pushRenderPassCommands(vk, *renderCommandBuffer, *renderPass, *framebuffer, subpassRenderers, renderPos, renderSize, renderPassClearValues, config.renderTypes);
endCommandBuffer(vk, *renderCommandBuffer);
beginCommandBuffer(vk, *readImagesToBuffersCommandBuffer, (VkCommandBufferUsageFlags)0, DE_NULL, 0, DE_NULL, VK_FALSE, (VkQueryControlFlags)0, (VkQueryPipelineStatisticFlags)0);
pushReadImagesToBuffers(vk, *readImagesToBuffersCommandBuffer, queueIndex, attachmentResources, renderPassInfo.getAttachments(), attachmentIsLazy, targetSize);
endCommandBuffer(vk, *readImagesToBuffersCommandBuffer);
{
const VkCommandBuffer commandBuffers[] =
{
*initializeImagesCommandBuffer,
*renderCommandBuffer,
*readImagesToBuffersCommandBuffer
};
const Unique<VkFence> fence (createFence(vk, device, 0u));
queueSubmit(vk, queue, DE_LENGTH_OF_ARRAY(commandBuffers), commandBuffers, *fence);
waitForFences(vk, device, 1, &fence.get(), VK_TRUE, ~0ull);
}
}
if (logAndVerifyImages(log, vk, device, attachmentResources, attachmentIsLazy, renderPassInfo, renderPassClearValues, imageClearValues, subpassRenderInfo, targetSize, config))
return tcu::TestStatus::pass("Pass");
else
return tcu::TestStatus::fail("Result verification failed");
}
}
static const VkFormat s_coreColorFormats[] =
{
VK_FORMAT_R5G6B5_UNORM_PACK16,
VK_FORMAT_R8_UNORM,
VK_FORMAT_R8_SNORM,
VK_FORMAT_R8_UINT,
VK_FORMAT_R8_SINT,
VK_FORMAT_R8G8_UNORM,
VK_FORMAT_R8G8_SNORM,
VK_FORMAT_R8G8_UINT,
VK_FORMAT_R8G8_SINT,
VK_FORMAT_R8G8B8A8_UNORM,
VK_FORMAT_R8G8B8A8_SNORM,
VK_FORMAT_R8G8B8A8_UINT,
VK_FORMAT_R8G8B8A8_SINT,
VK_FORMAT_R8G8B8A8_SRGB,
VK_FORMAT_A8B8G8R8_UNORM_PACK32,
VK_FORMAT_A8B8G8R8_SNORM_PACK32,
VK_FORMAT_A8B8G8R8_UINT_PACK32,
VK_FORMAT_A8B8G8R8_SINT_PACK32,
VK_FORMAT_A8B8G8R8_SRGB_PACK32,
VK_FORMAT_B8G8R8A8_UNORM,
VK_FORMAT_B8G8R8A8_SRGB,
VK_FORMAT_A2R10G10B10_UNORM_PACK32,
VK_FORMAT_A2B10G10R10_UNORM_PACK32,
VK_FORMAT_A2B10G10R10_UINT_PACK32,
VK_FORMAT_R16_UNORM,
VK_FORMAT_R16_SNORM,
VK_FORMAT_R16_UINT,
VK_FORMAT_R16_SINT,
VK_FORMAT_R16_SFLOAT,
VK_FORMAT_R16G16_UNORM,
VK_FORMAT_R16G16_SNORM,
VK_FORMAT_R16G16_UINT,
VK_FORMAT_R16G16_SINT,
VK_FORMAT_R16G16_SFLOAT,
VK_FORMAT_R16G16B16A16_UNORM,
VK_FORMAT_R16G16B16A16_SNORM,
VK_FORMAT_R16G16B16A16_UINT,
VK_FORMAT_R16G16B16A16_SINT,
VK_FORMAT_R16G16B16A16_SFLOAT,
VK_FORMAT_R32_UINT,
VK_FORMAT_R32_SINT,
VK_FORMAT_R32_SFLOAT,
VK_FORMAT_R32G32_UINT,
VK_FORMAT_R32G32_SINT,
VK_FORMAT_R32G32_SFLOAT,
VK_FORMAT_R32G32B32A32_UINT,
VK_FORMAT_R32G32B32A32_SINT,
VK_FORMAT_R32G32B32A32_SFLOAT
};
static const VkFormat s_coreDepthStencilFormats[] =
{
VK_FORMAT_D16_UNORM,
VK_FORMAT_X8_D24_UNORM_PACK32,
VK_FORMAT_D32_SFLOAT,
VK_FORMAT_D24_UNORM_S8_UINT,
VK_FORMAT_D32_SFLOAT_S8_UINT
};
de::MovePtr<tcu::TestCaseGroup> createAttachmentTestCaseGroup (tcu::TestContext& testCtx)
{
const deUint32 attachmentCounts[] = { 1, 3, 4, 8 };
const VkAttachmentLoadOp loadOps[] =
{
VK_ATTACHMENT_LOAD_OP_LOAD,
VK_ATTACHMENT_LOAD_OP_CLEAR,
VK_ATTACHMENT_LOAD_OP_DONT_CARE
};
const VkAttachmentStoreOp storeOps[] =
{
VK_ATTACHMENT_STORE_OP_STORE,
VK_ATTACHMENT_STORE_OP_DONT_CARE
};
const VkImageLayout initialAndFinalColorLayouts[] =
{
VK_IMAGE_LAYOUT_GENERAL,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
};
const VkImageLayout initialAndFinalDepthStencilLayouts[] =
{
VK_IMAGE_LAYOUT_GENERAL,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
};
const VkImageLayout subpassLayouts[] =
{
VK_IMAGE_LAYOUT_GENERAL,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
};
const VkImageLayout depthStencilLayouts[] =
{
VK_IMAGE_LAYOUT_GENERAL,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
};
const TestConfig::RenderTypes renderCommands[] =
{
TestConfig::RENDERTYPES_NONE,
TestConfig::RENDERTYPES_CLEAR,
TestConfig::RENDERTYPES_DRAW,
TestConfig::RENDERTYPES_CLEAR|TestConfig::RENDERTYPES_DRAW,
};
const TestConfig::CommandBufferTypes commandBuffers[] =
{
TestConfig::COMMANDBUFFERTYPES_INLINE,
TestConfig::COMMANDBUFFERTYPES_SECONDARY,
TestConfig::COMMANDBUFFERTYPES_INLINE|TestConfig::COMMANDBUFFERTYPES_SECONDARY
};
const TestConfig::ImageMemory imageMemories[] =
{
TestConfig::IMAGEMEMORY_STRICT,
TestConfig::IMAGEMEMORY_LAZY,
TestConfig::IMAGEMEMORY_STRICT|TestConfig::IMAGEMEMORY_LAZY
};
const UVec2 targetSizes[] =
{
UVec2(64, 64),
UVec2(63, 65)
};
const UVec2 renderPositions[] =
{
UVec2(0, 0),
UVec2(3, 17)
};
const UVec2 renderSizes[] =
{
UVec2(32, 32),
UVec2(60, 47)
};
de::Random rng (1433774382u);
de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "attachment", "Attachment format and count tests with load and store ops and image layouts"));
for (size_t attachmentCountNdx = 0; attachmentCountNdx < DE_LENGTH_OF_ARRAY(attachmentCounts); attachmentCountNdx++)
{
const deUint32 attachmentCount = attachmentCounts[attachmentCountNdx];
const deUint32 testCaseCount = (attachmentCount == 1 ? 100 : 200);
de::MovePtr<tcu::TestCaseGroup> attachmentCountGroup (new tcu::TestCaseGroup(testCtx, de::toString(attachmentCount).c_str(), de::toString(attachmentCount).c_str()));
for (size_t testCaseNdx = 0; testCaseNdx < testCaseCount; testCaseNdx++)
{
const bool useDepthStencil = rng.getBool();
VkImageLayout depthStencilLayout = VK_IMAGE_LAYOUT_GENERAL;
vector<Attachment> attachments;
vector<AttachmentReference> colorAttachmentReferences;
for (size_t attachmentNdx = 0; attachmentNdx < attachmentCount; attachmentNdx++)
{
const VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT;
const VkFormat format = rng.choose<VkFormat>(DE_ARRAY_BEGIN(s_coreColorFormats), DE_ARRAY_END(s_coreColorFormats));
const VkAttachmentLoadOp loadOp = rng.choose<VkAttachmentLoadOp>(DE_ARRAY_BEGIN(loadOps), DE_ARRAY_END(loadOps));
const VkAttachmentStoreOp storeOp = rng.choose<VkAttachmentStoreOp>(DE_ARRAY_BEGIN(storeOps), DE_ARRAY_END(storeOps));
const VkImageLayout initialLayout = rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(initialAndFinalColorLayouts), DE_ARRAY_END(initialAndFinalColorLayouts));
const VkImageLayout finalizeLayout = rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(initialAndFinalColorLayouts), DE_ARRAY_END(initialAndFinalColorLayouts));
const VkImageLayout subpassLayout = rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(subpassLayouts), DE_ARRAY_END(subpassLayouts));
const VkAttachmentLoadOp stencilLoadOp = rng.choose<VkAttachmentLoadOp>(DE_ARRAY_BEGIN(loadOps), DE_ARRAY_END(loadOps));
const VkAttachmentStoreOp stencilStoreOp = rng.choose<VkAttachmentStoreOp>(DE_ARRAY_BEGIN(storeOps), DE_ARRAY_END(storeOps));
attachments.push_back(Attachment(format, sampleCount, loadOp, storeOp, stencilLoadOp, stencilStoreOp, initialLayout, finalizeLayout));
colorAttachmentReferences.push_back(AttachmentReference((deUint32)attachmentNdx, subpassLayout));
}
if (useDepthStencil)
{
const VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT;
const VkFormat format = rng.choose<VkFormat>(DE_ARRAY_BEGIN(s_coreDepthStencilFormats), DE_ARRAY_END(s_coreDepthStencilFormats));
const VkAttachmentLoadOp loadOp = rng.choose<VkAttachmentLoadOp>(DE_ARRAY_BEGIN(loadOps), DE_ARRAY_END(loadOps));
const VkAttachmentStoreOp storeOp = rng.choose<VkAttachmentStoreOp>(DE_ARRAY_BEGIN(storeOps), DE_ARRAY_END(storeOps));
const VkImageLayout initialLayout = rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(initialAndFinalDepthStencilLayouts), DE_ARRAY_END(initialAndFinalDepthStencilLayouts));
const VkImageLayout finalizeLayout = rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(initialAndFinalDepthStencilLayouts), DE_ARRAY_END(initialAndFinalDepthStencilLayouts));
const VkAttachmentLoadOp stencilLoadOp = rng.choose<VkAttachmentLoadOp>(DE_ARRAY_BEGIN(loadOps), DE_ARRAY_END(loadOps));
const VkAttachmentStoreOp stencilStoreOp = rng.choose<VkAttachmentStoreOp>(DE_ARRAY_BEGIN(storeOps), DE_ARRAY_END(storeOps));
depthStencilLayout = rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(depthStencilLayouts), DE_ARRAY_END(depthStencilLayouts));
attachments.push_back(Attachment(format, sampleCount, loadOp, storeOp, stencilLoadOp, stencilStoreOp, initialLayout, finalizeLayout));
}
{
const TestConfig::RenderTypes render = rng.choose<TestConfig::RenderTypes>(DE_ARRAY_BEGIN(renderCommands), DE_ARRAY_END(renderCommands));
const TestConfig::CommandBufferTypes commandBuffer = rng.choose<TestConfig::CommandBufferTypes>(DE_ARRAY_BEGIN(commandBuffers), DE_ARRAY_END(commandBuffers));
const TestConfig::ImageMemory imageMemory = rng.choose<TestConfig::ImageMemory>(DE_ARRAY_BEGIN(imageMemories), DE_ARRAY_END(imageMemories));
const vector<Subpass> subpasses (1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector<AttachmentReference>(), colorAttachmentReferences, vector<AttachmentReference>(), AttachmentReference((useDepthStencil ? (deUint32)(attachments.size() - 1) : VK_ATTACHMENT_UNUSED), depthStencilLayout), vector<AttachmentReference>()));
const vector<SubpassDependency> deps;
const string testCaseName = de::toString(attachmentCountNdx * testCaseCount + testCaseNdx);
const RenderPass renderPass (attachments, subpasses, deps);
const UVec2 targetSize = rng.choose<UVec2>(DE_ARRAY_BEGIN(targetSizes), DE_ARRAY_END(targetSizes));
const UVec2 renderPos = rng.choose<UVec2>(DE_ARRAY_BEGIN(renderPositions), DE_ARRAY_END(renderPositions));
const UVec2 renderSize = rng.choose<UVec2>(DE_ARRAY_BEGIN(renderSizes), DE_ARRAY_END(renderSizes));
addFunctionCaseWithPrograms<TestConfig>(attachmentCountGroup.get(), testCaseName.c_str(), testCaseName.c_str(), createTestShaders, renderPassTest, TestConfig(renderPass, render, commandBuffer, imageMemory, targetSize, renderPos, renderSize, 1293809));
}
}
group->addChild(attachmentCountGroup.release());
}
return group;
}
de::MovePtr<tcu::TestCaseGroup> createAttachmentAllocationTestGroup (tcu::TestContext& testCtx)
{
const deUint32 attachmentCounts[] = { 4, 8 };
const VkAttachmentLoadOp loadOps[] =
{
VK_ATTACHMENT_LOAD_OP_LOAD,
VK_ATTACHMENT_LOAD_OP_CLEAR,
VK_ATTACHMENT_LOAD_OP_DONT_CARE
};
const VkAttachmentStoreOp storeOps[] =
{
VK_ATTACHMENT_STORE_OP_STORE,
VK_ATTACHMENT_STORE_OP_DONT_CARE
};
const VkImageLayout initialAndFinalColorLayouts[] =
{
VK_IMAGE_LAYOUT_GENERAL,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
};
const VkImageLayout subpassLayouts[] =
{
VK_IMAGE_LAYOUT_GENERAL,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
};
enum AllocationType
{
// Each pass uses one more attachmen than previous one
ALLOCATIONTYPE_GROW,
// Each pass uses one less attachment than previous one
ALLOCATIONTYPE_SHRINK,
// Each pass drops one attachment and picks up new one
ALLOCATIONTYPE_ROLL,
// Start by growing and end by shrinking
ALLOCATIONTYPE_GROW_SHRINK
};
const AllocationType allocationTypes[] =
{
ALLOCATIONTYPE_GROW,
ALLOCATIONTYPE_SHRINK,
ALLOCATIONTYPE_ROLL,
ALLOCATIONTYPE_GROW_SHRINK
};
const char* const allocationTypeStr[] =
{
"grow",
"shrink",
"roll",
"grow_shrink"
};
const TestConfig::RenderTypes renderCommands[] =
{
TestConfig::RENDERTYPES_NONE,
TestConfig::RENDERTYPES_CLEAR,
TestConfig::RENDERTYPES_DRAW,
TestConfig::RENDERTYPES_CLEAR|TestConfig::RENDERTYPES_DRAW,
};
const TestConfig::CommandBufferTypes commandBuffers[] =
{
TestConfig::COMMANDBUFFERTYPES_INLINE,
TestConfig::COMMANDBUFFERTYPES_SECONDARY,
TestConfig::COMMANDBUFFERTYPES_INLINE|TestConfig::COMMANDBUFFERTYPES_SECONDARY
};
const TestConfig::ImageMemory imageMemories[] =
{
TestConfig::IMAGEMEMORY_STRICT,
TestConfig::IMAGEMEMORY_LAZY,
TestConfig::IMAGEMEMORY_STRICT|TestConfig::IMAGEMEMORY_LAZY
};
const UVec2 targetSizes[] =
{
UVec2(64, 64),
UVec2(63, 65)
};
const UVec2 renderPositions[] =
{
UVec2(0, 0),
UVec2(3, 17)
};
const UVec2 renderSizes[] =
{
UVec2(32, 32),
UVec2(60, 47)
};
de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "attachment_allocation", "Attachment allocation tests"));
de::Random rng (3700649827u);
for (size_t allocationTypeNdx = 0; allocationTypeNdx < DE_LENGTH_OF_ARRAY(allocationTypes); allocationTypeNdx++)
{
const AllocationType allocationType = allocationTypes[allocationTypeNdx];
const size_t testCaseCount = 100;
de::MovePtr<tcu::TestCaseGroup> allocationTypeGroup (new tcu::TestCaseGroup(testCtx, allocationTypeStr[allocationTypeNdx], allocationTypeStr[allocationTypeNdx]));
for (size_t testCaseNdx = 0; testCaseNdx < testCaseCount; testCaseNdx++)
{
const deUint32 attachmentCount = rng.choose<deUint32>(DE_ARRAY_BEGIN(attachmentCounts), DE_ARRAY_END(attachmentCounts));
vector<Attachment> attachments;
vector<Subpass> subpasses;
for (size_t attachmentNdx = 0; attachmentNdx < attachmentCount; attachmentNdx++)
{
const VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT;
const VkFormat format = rng.choose<VkFormat>(DE_ARRAY_BEGIN(s_coreColorFormats), DE_ARRAY_END(s_coreColorFormats));
const VkAttachmentLoadOp loadOp = rng.choose<VkAttachmentLoadOp>(DE_ARRAY_BEGIN(loadOps), DE_ARRAY_END(loadOps));
const VkAttachmentStoreOp storeOp = rng.choose<VkAttachmentStoreOp>(DE_ARRAY_BEGIN(storeOps), DE_ARRAY_END(storeOps));
const VkImageLayout initialLayout = rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(initialAndFinalColorLayouts), DE_ARRAY_END(initialAndFinalColorLayouts));
const VkImageLayout finalizeLayout = rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(initialAndFinalColorLayouts), DE_ARRAY_END(initialAndFinalColorLayouts));
const VkAttachmentLoadOp stencilLoadOp = rng.choose<VkAttachmentLoadOp>(DE_ARRAY_BEGIN(loadOps), DE_ARRAY_END(loadOps));
const VkAttachmentStoreOp stencilStoreOp = rng.choose<VkAttachmentStoreOp>(DE_ARRAY_BEGIN(storeOps), DE_ARRAY_END(storeOps));
attachments.push_back(Attachment(format, sampleCount, loadOp, storeOp, stencilLoadOp, stencilStoreOp, initialLayout, finalizeLayout));
}
if (allocationType == ALLOCATIONTYPE_GROW)
{
for (size_t subpassNdx = 0; subpassNdx < attachmentCount; subpassNdx++)
{
vector<AttachmentReference> colorAttachmentReferences;
for (size_t attachmentNdx = 0; attachmentNdx < subpassNdx + 1; attachmentNdx++)
{
const VkImageLayout subpassLayout = rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(subpassLayouts), DE_ARRAY_END(subpassLayouts));
colorAttachmentReferences.push_back(AttachmentReference((deUint32)attachmentNdx, subpassLayout));
}
subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector<AttachmentReference>(), colorAttachmentReferences, vector<AttachmentReference>(), AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL), vector<AttachmentReference>()));
}
}
else if (allocationType == ALLOCATIONTYPE_SHRINK)
{
for (size_t subpassNdx = 0; subpassNdx < attachmentCount; subpassNdx++)
{
vector<AttachmentReference> colorAttachmentReferences;
for (size_t attachmentNdx = 0; attachmentNdx < (attachmentCount - subpassNdx); attachmentNdx++)
{
const VkImageLayout subpassLayout = rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(subpassLayouts), DE_ARRAY_END(subpassLayouts));
colorAttachmentReferences.push_back(AttachmentReference((deUint32)attachmentNdx, subpassLayout));
}
subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector<AttachmentReference>(), colorAttachmentReferences, vector<AttachmentReference>(), AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL), vector<AttachmentReference>()));
}
}
else if (allocationType == ALLOCATIONTYPE_ROLL)
{
for (size_t subpassNdx = 0; subpassNdx < attachmentCount / 2; subpassNdx++)
{
vector<AttachmentReference> colorAttachmentReferences;
for (size_t attachmentNdx = 0; attachmentNdx < attachmentCount / 2; attachmentNdx++)
{
const VkImageLayout subpassLayout = rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(subpassLayouts), DE_ARRAY_END(subpassLayouts));
colorAttachmentReferences.push_back(AttachmentReference((deUint32)(subpassNdx + attachmentNdx), subpassLayout));
}
subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector<AttachmentReference>(), colorAttachmentReferences, vector<AttachmentReference>(), AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL), vector<AttachmentReference>()));
}
}
else if (allocationType == ALLOCATIONTYPE_GROW_SHRINK)
{
for (size_t subpassNdx = 0; subpassNdx < attachmentCount; subpassNdx++)
{
vector<AttachmentReference> colorAttachmentReferences;
for (size_t attachmentNdx = 0; attachmentNdx < subpassNdx + 1; attachmentNdx++)
{
const VkImageLayout subpassLayout = rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(subpassLayouts), DE_ARRAY_END(subpassLayouts));
colorAttachmentReferences.push_back(AttachmentReference((deUint32)attachmentNdx, subpassLayout));
}
subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector<AttachmentReference>(), colorAttachmentReferences, vector<AttachmentReference>(), AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL), vector<AttachmentReference>()));
}
for (size_t subpassNdx = 0; subpassNdx < attachmentCount; subpassNdx++)
{
vector<AttachmentReference> colorAttachmentReferences;
for (size_t attachmentNdx = 0; attachmentNdx < (attachmentCount - subpassNdx); attachmentNdx++)
{
const VkImageLayout subpassLayout = rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(subpassLayouts), DE_ARRAY_END(subpassLayouts));
colorAttachmentReferences.push_back(AttachmentReference((deUint32)attachmentNdx, subpassLayout));
}
subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector<AttachmentReference>(), colorAttachmentReferences, vector<AttachmentReference>(), AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL), vector<AttachmentReference>()));
}
}
else
DE_FATAL("Unknown allocation type");
{
const TestConfig::RenderTypes render = rng.choose<TestConfig::RenderTypes>(DE_ARRAY_BEGIN(renderCommands), DE_ARRAY_END(renderCommands));
const TestConfig::CommandBufferTypes commandBuffer = rng.choose<TestConfig::CommandBufferTypes>(DE_ARRAY_BEGIN(commandBuffers), DE_ARRAY_END(commandBuffers));
const TestConfig::ImageMemory imageMemory = rng.choose<TestConfig::ImageMemory>(DE_ARRAY_BEGIN(imageMemories), DE_ARRAY_END(imageMemories));
const string testCaseName = de::toString(testCaseNdx);
const UVec2 targetSize = rng.choose<UVec2>(DE_ARRAY_BEGIN(targetSizes), DE_ARRAY_END(targetSizes));
const UVec2 renderPos = rng.choose<UVec2>(DE_ARRAY_BEGIN(renderPositions), DE_ARRAY_END(renderPositions));
const UVec2 renderSize = rng.choose<UVec2>(DE_ARRAY_BEGIN(renderSizes), DE_ARRAY_END(renderSizes));
vector<SubpassDependency> deps;
for (size_t subpassNdx = 0; subpassNdx < subpasses.size() - 1; subpassNdx++)
{
const bool byRegion = rng.getBool();
deps.push_back(SubpassDependency((deUint32)subpassNdx, (deUint32)subpassNdx + 1,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
| VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
| VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, // \todo [pyry] Correct?
byRegion ? (VkBool32)VK_TRUE : (VkBool32)VK_FALSE));
}
const RenderPass renderPass (attachments, subpasses, deps);
addFunctionCaseWithPrograms<TestConfig>(allocationTypeGroup.get(), testCaseName.c_str(), testCaseName.c_str(), createTestShaders, renderPassTest, TestConfig(renderPass, render, commandBuffer, imageMemory, targetSize, renderPos, renderSize, 80329));
}
}
group->addChild(allocationTypeGroup.release());
}
return group;
}
de::MovePtr<tcu::TestCaseGroup> createSimpleTestGroup (tcu::TestContext& testCtx)
{
const UVec2 targetSize (64, 64);
const UVec2 renderPos (0, 0);
const UVec2 renderSize (64, 64);
de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "simple", "Simple basic render pass tests"));
// color
{
const RenderPass renderPass (vector<Attachment>(1, Attachment(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_DONT_CARE,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)),
vector<Subpass>(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
0u,
vector<AttachmentReference>(),
vector<AttachmentReference>(1, AttachmentReference(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)),
vector<AttachmentReference>(),
AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL),
vector<AttachmentReference>())),
vector<SubpassDependency>());
addFunctionCaseWithPrograms<TestConfig>(group.get(), "color", "Single color attachment case.", createTestShaders, renderPassTest, TestConfig(renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239));
}
// depth
{
const RenderPass renderPass (vector<Attachment>(1, Attachment(VK_FORMAT_X8_D24_UNORM_PACK32,
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_DONT_CARE,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)),
vector<Subpass>(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
0u,
vector<AttachmentReference>(),
vector<AttachmentReference>(),
vector<AttachmentReference>(),
AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL),
vector<AttachmentReference>())),
vector<SubpassDependency>());
addFunctionCaseWithPrograms<TestConfig>(group.get(), "depth", "Single depth attachment case.", createTestShaders, renderPassTest, TestConfig(renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239));
}
// stencil
{
const RenderPass renderPass (vector<Attachment>(1, Attachment(VK_FORMAT_S8_UINT,
VK_SAMPLE_COUNT_1_BIT,
VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_DONT_CARE,
VK_ATTACHMENT_LOAD_OP_CLEAR,
VK_ATTACHMENT_STORE_OP_STORE,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)),
vector<Subpass>(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
0u,
vector<AttachmentReference>(),
vector<AttachmentReference>(),
vector<AttachmentReference>(),
AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL),
vector<AttachmentReference>())),
vector<SubpassDependency>());
addFunctionCaseWithPrograms<TestConfig>(group.get(), "stencil", "Single stencil attachment case.", createTestShaders, renderPassTest, TestConfig(renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239));
}
// depth_stencil
{
const RenderPass renderPass (vector<Attachment>(1, Attachment(VK_FORMAT_D24_UNORM_S8_UINT,
VK_SAMPLE_COUNT_1_BIT,
VK_ATTACHMENT_LOAD_OP_CLEAR,
VK_ATTACHMENT_STORE_OP_STORE,
VK_ATTACHMENT_LOAD_OP_CLEAR,
VK_ATTACHMENT_STORE_OP_STORE,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)),
vector<Subpass>(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
0u,
vector<AttachmentReference>(),
vector<AttachmentReference>(),
vector<AttachmentReference>(),
AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL),
vector<AttachmentReference>())),
vector<SubpassDependency>());
addFunctionCaseWithPrograms<TestConfig>(group.get(), "depth_stencil", "Single depth stencil attachment case.", createTestShaders, renderPassTest, TestConfig(renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239));
}
// color_depth
{
const Attachment attachments[] =
{
Attachment(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_DONT_CARE,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL),
Attachment(VK_FORMAT_X8_D24_UNORM_PACK32,
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_DONT_CARE,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL),
};
const RenderPass renderPass (vector<Attachment>(DE_ARRAY_BEGIN(attachments), DE_ARRAY_END(attachments)),
vector<Subpass>(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
0u,
vector<AttachmentReference>(),
vector<AttachmentReference>(1, AttachmentReference(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)),
vector<AttachmentReference>(),
AttachmentReference(1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL),
vector<AttachmentReference>())),
vector<SubpassDependency>());
addFunctionCaseWithPrograms<TestConfig>(group.get(), "color_depth", "Color and depth attachment case.", createTestShaders, renderPassTest, TestConfig(renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239));
}
// color_stencil
{
const Attachment attachments[] =
{
Attachment(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_DONT_CARE,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL),
Attachment(VK_FORMAT_S8_UINT,
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_DONT_CARE,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL),
};
const RenderPass renderPass (vector<Attachment>(DE_ARRAY_BEGIN(attachments), DE_ARRAY_END(attachments)),
vector<Subpass>(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
0u,
vector<AttachmentReference>(),
vector<AttachmentReference>(1, AttachmentReference(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)),
vector<AttachmentReference>(),
AttachmentReference(1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL),
vector<AttachmentReference>())),
vector<SubpassDependency>());
addFunctionCaseWithPrograms<TestConfig>(group.get(), "color_stencil", "Color and stencil attachment case.", createTestShaders, renderPassTest, TestConfig(renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239));
}
// color_depth_stencil
{
const Attachment attachments[] =
{
Attachment(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_DONT_CARE,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL),
Attachment(VK_FORMAT_D24_UNORM_S8_UINT,
VK_SAMPLE_COUNT_1_BIT,
VK_ATTACHMENT_LOAD_OP_CLEAR,
VK_ATTACHMENT_STORE_OP_STORE,
VK_ATTACHMENT_LOAD_OP_CLEAR,
VK_ATTACHMENT_STORE_OP_STORE,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL),
};
const RenderPass renderPass (vector<Attachment>(DE_ARRAY_BEGIN(attachments), DE_ARRAY_END(attachments)),
vector<Subpass>(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
0u,
vector<AttachmentReference>(),
vector<AttachmentReference>(1, AttachmentReference(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)),
vector<AttachmentReference>(),
AttachmentReference(1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL),
vector<AttachmentReference>())),
vector<SubpassDependency>());
addFunctionCaseWithPrograms<TestConfig>(group.get(), "color_depth_stencil", "Color, depth and stencil attachment case.", createTestShaders, renderPassTest, TestConfig(renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239));
}
return group;
}
std::string formatToName (VkFormat format)
{
const std::string formatStr = de::toString(format);
const std::string prefix = "VK_FORMAT_";
DE_ASSERT(formatStr.substr(0, prefix.length()) == prefix);
return de::toLower(formatStr.substr(prefix.length()));
}
de::MovePtr<tcu::TestCaseGroup> createFormatTestGroup(tcu::TestContext& testCtx)
{
de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "formats", "Tests for different image formats."));
const UVec2 targetSize (64, 64);
const UVec2 renderPos (0, 0);
const UVec2 renderSize (64, 64);
const struct
{
const char* const str;
const VkAttachmentLoadOp op;
} loadOps[] =
{
{ "clear", VK_ATTACHMENT_LOAD_OP_CLEAR },
{ "load", VK_ATTACHMENT_LOAD_OP_LOAD },
{ "dont_care", VK_ATTACHMENT_LOAD_OP_DONT_CARE }
};
const struct
{
const char* const str;
const TestConfig::RenderTypes types;
} renderTypes[] =
{
{ "clear", TestConfig::RENDERTYPES_CLEAR },
{ "draw", TestConfig::RENDERTYPES_DRAW },
{ "clear_draw", TestConfig::RENDERTYPES_CLEAR|TestConfig::RENDERTYPES_DRAW }
};
// Color formats
for (size_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(s_coreColorFormats); formatNdx++)
{
const VkFormat format = s_coreColorFormats[formatNdx];
de::MovePtr<tcu::TestCaseGroup> formatGroup (new tcu::TestCaseGroup(testCtx, formatToName(format).c_str(), de::toString(format).c_str()));
for (size_t loadOpNdx = 0; loadOpNdx < DE_LENGTH_OF_ARRAY(loadOps); loadOpNdx++)
{
const VkAttachmentLoadOp loadOp = loadOps[loadOpNdx].op;
de::MovePtr<tcu::TestCaseGroup> loadOpGroup (new tcu::TestCaseGroup(testCtx, loadOps[loadOpNdx].str, loadOps[loadOpNdx].str));
for (size_t renderTypeNdx = 0; renderTypeNdx < DE_LENGTH_OF_ARRAY(renderTypes); renderTypeNdx++)
{
const RenderPass renderPass (vector<Attachment>(1, Attachment(format,
VK_SAMPLE_COUNT_1_BIT,
loadOp,
VK_ATTACHMENT_STORE_OP_STORE,
VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_DONT_CARE,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)),
vector<Subpass>(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
0u,
vector<AttachmentReference>(),
vector<AttachmentReference>(1, AttachmentReference(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)),
vector<AttachmentReference>(),
AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL),
vector<AttachmentReference>())),
vector<SubpassDependency>());
addFunctionCaseWithPrograms<TestConfig>(loadOpGroup.get(), renderTypes[renderTypeNdx].str, renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, TestConfig(renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239));
}
formatGroup->addChild(loadOpGroup.release());
}
group->addChild(formatGroup.release());
}
// Depth stencil formats
for (size_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(s_coreDepthStencilFormats); formatNdx++)
{
const VkFormat vkFormat = s_coreDepthStencilFormats[formatNdx];
de::MovePtr<tcu::TestCaseGroup> formatGroup (new tcu::TestCaseGroup(testCtx, formatToName(vkFormat).c_str(), de::toString(vkFormat).c_str()));
for (size_t loadOpNdx = 0; loadOpNdx < DE_LENGTH_OF_ARRAY(loadOps); loadOpNdx++)
{
const VkAttachmentLoadOp loadOp = loadOps[loadOpNdx].op;
de::MovePtr<tcu::TestCaseGroup> loadOpGroup (new tcu::TestCaseGroup(testCtx, loadOps[loadOpNdx].str, loadOps[loadOpNdx].str));
for (size_t renderTypeNdx = 0; renderTypeNdx < DE_LENGTH_OF_ARRAY(renderTypes); renderTypeNdx++)
{
const tcu::TextureFormat format = mapVkFormat(vkFormat);
const bool isStencilAttachment = hasStencilComponent(format.order);
const bool isDepthAttachment = hasDepthComponent(format.order);
const RenderPass renderPass (vector<Attachment>(1, Attachment(vkFormat,
VK_SAMPLE_COUNT_1_BIT,
isDepthAttachment ? loadOp : VK_ATTACHMENT_LOAD_OP_DONT_CARE,
isDepthAttachment ? VK_ATTACHMENT_STORE_OP_STORE :VK_ATTACHMENT_STORE_OP_DONT_CARE,
isStencilAttachment ? loadOp : VK_ATTACHMENT_LOAD_OP_DONT_CARE,
isStencilAttachment ? VK_ATTACHMENT_STORE_OP_STORE :VK_ATTACHMENT_STORE_OP_DONT_CARE,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)),
vector<Subpass>(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
0u,
vector<AttachmentReference>(),
vector<AttachmentReference>(),
vector<AttachmentReference>(),
AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL),
vector<AttachmentReference>())),
vector<SubpassDependency>());
addFunctionCaseWithPrograms<TestConfig>(loadOpGroup.get(), renderTypes[renderTypeNdx].str, renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, TestConfig(renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239));
}
formatGroup->addChild(loadOpGroup.release());
}
group->addChild(formatGroup.release());
}
return group;
}
} // anonymous
tcu::TestCaseGroup* createRenderPassTests (tcu::TestContext& testCtx)
{
de::MovePtr<tcu::TestCaseGroup> renderpassTests (new tcu::TestCaseGroup(testCtx, "renderpass", "RenderPass Tests"));
renderpassTests->addChild(createSimpleTestGroup(testCtx).release());
renderpassTests->addChild(createFormatTestGroup(testCtx).release());
renderpassTests->addChild(createAttachmentTestCaseGroup(testCtx).release());
renderpassTests->addChild(createAttachmentAllocationTestGroup(testCtx).release());
return renderpassTests.release();
}
} // vkt