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;