blob: 8615909a41270d42c02ad162d341c233cbcd433f [file] [log] [blame]
//
// Copyright 2018 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// vk_cache_utils.cpp:
// Contains the classes for the Pipeline State Object cache as well as the RenderPass cache.
// Also contains the structures for the packed descriptions for the RenderPass and Pipeline.
//
#include "libANGLE/renderer/vulkan/vk_cache_utils.h"
#include "common/aligned_memory.h"
#include "libANGLE/SizedMRUCache.h"
#include "libANGLE/VertexAttribute.h"
#include "libANGLE/renderer/vulkan/ProgramVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/vk_format_utils.h"
namespace rx
{
namespace vk
{
namespace
{
VkSampleCountFlagBits ConvertSamples(GLint sampleCount)
{
switch (sampleCount)
{
case 0:
case 1:
return VK_SAMPLE_COUNT_1_BIT;
case 2:
return VK_SAMPLE_COUNT_2_BIT;
case 4:
return VK_SAMPLE_COUNT_4_BIT;
case 8:
return VK_SAMPLE_COUNT_8_BIT;
case 16:
return VK_SAMPLE_COUNT_16_BIT;
case 32:
return VK_SAMPLE_COUNT_32_BIT;
default:
UNREACHABLE();
return VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM;
}
}
void UnpackAttachmentDesc(VkAttachmentDescription *desc,
const vk::PackedAttachmentDesc &packedDesc,
const vk::PackedAttachmentOpsDesc &ops)
{
desc->flags = static_cast<VkAttachmentDescriptionFlags>(packedDesc.flags);
desc->format = static_cast<VkFormat>(packedDesc.format);
desc->samples = ConvertSamples(packedDesc.samples);
desc->loadOp = static_cast<VkAttachmentLoadOp>(ops.loadOp);
desc->storeOp = static_cast<VkAttachmentStoreOp>(ops.storeOp);
desc->stencilLoadOp = static_cast<VkAttachmentLoadOp>(ops.stencilLoadOp);
desc->stencilStoreOp = static_cast<VkAttachmentStoreOp>(ops.stencilStoreOp);
desc->initialLayout = static_cast<VkImageLayout>(ops.initialLayout);
desc->finalLayout = static_cast<VkImageLayout>(ops.finalLayout);
}
void UnpackStencilState(const vk::PackedStencilOpState &packedState, VkStencilOpState *stateOut)
{
stateOut->failOp = static_cast<VkStencilOp>(packedState.failOp);
stateOut->passOp = static_cast<VkStencilOp>(packedState.passOp);
stateOut->depthFailOp = static_cast<VkStencilOp>(packedState.depthFailOp);
stateOut->compareOp = static_cast<VkCompareOp>(packedState.compareOp);
stateOut->compareMask = packedState.compareMask;
stateOut->writeMask = packedState.writeMask;
stateOut->reference = packedState.reference;
}
void UnpackBlendAttachmentState(vk::PackedColorBlendAttachmentState &packedState,
VkPipelineColorBlendAttachmentState *stateOut)
{
stateOut->blendEnable = static_cast<VkBool32>(packedState.blendEnable);
stateOut->srcColorBlendFactor = static_cast<VkBlendFactor>(packedState.srcColorBlendFactor);
stateOut->dstColorBlendFactor = static_cast<VkBlendFactor>(packedState.dstColorBlendFactor);
stateOut->colorBlendOp = static_cast<VkBlendOp>(packedState.colorBlendOp);
stateOut->srcAlphaBlendFactor = static_cast<VkBlendFactor>(packedState.srcAlphaBlendFactor);
stateOut->dstAlphaBlendFactor = static_cast<VkBlendFactor>(packedState.dstAlphaBlendFactor);
stateOut->alphaBlendOp = static_cast<VkBlendOp>(packedState.alphaBlendOp);
stateOut->colorWriteMask = static_cast<VkColorComponentFlags>(packedState.colorWriteMask);
}
Error InitializeRenderPassFromDesc(VkDevice device,
const RenderPassDesc &desc,
const AttachmentOpsArray &ops,
RenderPass *renderPass)
{
uint32_t attachmentCount = desc.attachmentCount();
ASSERT(attachmentCount > 0);
gl::DrawBuffersArray<VkAttachmentReference> colorAttachmentRefs;
for (uint32_t colorIndex = 0; colorIndex < desc.colorAttachmentCount(); ++colorIndex)
{
VkAttachmentReference &colorRef = colorAttachmentRefs[colorIndex];
colorRef.attachment = colorIndex;
colorRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
}
VkAttachmentReference depthStencilAttachmentRef;
if (desc.depthStencilAttachmentCount() > 0)
{
ASSERT(desc.depthStencilAttachmentCount() == 1);
depthStencilAttachmentRef.attachment = desc.colorAttachmentCount();
depthStencilAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
}
VkSubpassDescription subpassDesc;
subpassDesc.flags = 0;
subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpassDesc.inputAttachmentCount = 0;
subpassDesc.pInputAttachments = nullptr;
subpassDesc.colorAttachmentCount = desc.colorAttachmentCount();
subpassDesc.pColorAttachments = colorAttachmentRefs.data();
subpassDesc.pResolveAttachments = nullptr;
subpassDesc.pDepthStencilAttachment =
(desc.depthStencilAttachmentCount() > 0 ? &depthStencilAttachmentRef : nullptr);
subpassDesc.preserveAttachmentCount = 0;
subpassDesc.pPreserveAttachments = nullptr;
// Unpack the packed and split representation into the format required by Vulkan.
gl::AttachmentArray<VkAttachmentDescription> attachmentDescs;
for (uint32_t colorIndex = 0; colorIndex < desc.colorAttachmentCount(); ++colorIndex)
{
UnpackAttachmentDesc(&attachmentDescs[colorIndex], desc[colorIndex], ops[colorIndex]);
}
if (desc.depthStencilAttachmentCount() > 0)
{
uint32_t depthStencilIndex = desc.colorAttachmentCount();
UnpackAttachmentDesc(&attachmentDescs[depthStencilIndex], desc[depthStencilIndex],
ops[depthStencilIndex]);
}
VkRenderPassCreateInfo createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.attachmentCount = attachmentCount;
createInfo.pAttachments = attachmentDescs.data();
createInfo.subpassCount = 1;
createInfo.pSubpasses = &subpassDesc;
createInfo.dependencyCount = 0;
createInfo.pDependencies = nullptr;
ANGLE_TRY(renderPass->init(device, createInfo));
return vk::NoError();
}
} // anonymous namespace
// RenderPassDesc implementation.
RenderPassDesc::RenderPassDesc()
{
UNUSED_VARIABLE(mPadding);
memset(this, 0, sizeof(RenderPassDesc));
}
RenderPassDesc::~RenderPassDesc()
{
}
RenderPassDesc::RenderPassDesc(const RenderPassDesc &other)
{
memcpy(this, &other, sizeof(RenderPassDesc));
}
void RenderPassDesc::packAttachment(uint32_t index, const vk::Format &format, GLsizei samples)
{
PackedAttachmentDesc &desc = mAttachmentDescs[index];
// TODO(jmadill): We would only need this flag for duplicated attachments.
desc.flags = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT;
ASSERT(desc.samples < std::numeric_limits<uint8_t>::max());
desc.samples = static_cast<uint8_t>(samples);
ASSERT(format.vkTextureFormat < std::numeric_limits<uint16_t>::max());
desc.format = static_cast<uint16_t>(format.vkTextureFormat);
}
void RenderPassDesc::packColorAttachment(const vk::Format &format, GLsizei samples)
{
ASSERT(mDepthStencilAttachmentCount == 0);
ASSERT(mColorAttachmentCount < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS);
packAttachment(mColorAttachmentCount++, format, samples);
}
void RenderPassDesc::packDepthStencilAttachment(const vk::Format &format, GLsizei samples)
{
ASSERT(mDepthStencilAttachmentCount == 0);
packAttachment(mDepthStencilAttachmentCount++, format, samples);
}
RenderPassDesc &RenderPassDesc::operator=(const RenderPassDesc &other)
{
memcpy(this, &other, sizeof(RenderPassDesc));
return *this;
}
size_t RenderPassDesc::hash() const
{
return angle::ComputeGenericHash(*this);
}
uint32_t RenderPassDesc::attachmentCount() const
{
return (mColorAttachmentCount + mDepthStencilAttachmentCount);
}
uint32_t RenderPassDesc::colorAttachmentCount() const
{
return mColorAttachmentCount;
}
uint32_t RenderPassDesc::depthStencilAttachmentCount() const
{
return mDepthStencilAttachmentCount;
}
const PackedAttachmentDesc &RenderPassDesc::operator[](size_t index) const
{
ASSERT(index < mAttachmentDescs.size());
return mAttachmentDescs[index];
}
bool operator==(const RenderPassDesc &lhs, const RenderPassDesc &rhs)
{
return (memcmp(&lhs, &rhs, sizeof(RenderPassDesc)) == 0);
}
// PipelineDesc implementation.
// Use aligned allocation and free so we can use the alignas keyword.
void *PipelineDesc::operator new(std::size_t size)
{
return angle::AlignedAlloc(size, 32);
}
void PipelineDesc::operator delete(void *ptr)
{
return angle::AlignedFree(ptr);
}
PipelineDesc::PipelineDesc()
{
memset(this, 0, sizeof(PipelineDesc));
}
PipelineDesc::~PipelineDesc()
{
}
PipelineDesc::PipelineDesc(const PipelineDesc &other)
{
memcpy(this, &other, sizeof(PipelineDesc));
}
PipelineDesc &PipelineDesc::operator=(const PipelineDesc &other)
{
memcpy(this, &other, sizeof(PipelineDesc));
return *this;
}
size_t PipelineDesc::hash() const
{
return angle::ComputeGenericHash(*this);
}
bool PipelineDesc::operator==(const PipelineDesc &other) const
{
return (memcmp(this, &other, sizeof(PipelineDesc)) == 0);
}
void PipelineDesc::initDefaults()
{
mInputAssemblyInfo.topology = static_cast<uint32_t>(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
mInputAssemblyInfo.primitiveRestartEnable = 0;
mRasterizationStateInfo.depthClampEnable = 0;
mRasterizationStateInfo.rasterizationDiscardEnable = 0;
mRasterizationStateInfo.polygonMode = static_cast<uint16_t>(VK_POLYGON_MODE_FILL);
mRasterizationStateInfo.cullMode = static_cast<uint16_t>(VK_CULL_MODE_NONE);
mRasterizationStateInfo.frontFace = static_cast<uint16_t>(VK_FRONT_FACE_CLOCKWISE);
mRasterizationStateInfo.depthBiasEnable = 0;
mRasterizationStateInfo.depthBiasConstantFactor = 0.0f;
mRasterizationStateInfo.depthBiasClamp = 0.0f;
mRasterizationStateInfo.depthBiasSlopeFactor = 0.0f;
mRasterizationStateInfo.lineWidth = 1.0f;
mMultisampleStateInfo.rasterizationSamples = 1;
mMultisampleStateInfo.sampleShadingEnable = 0;
mMultisampleStateInfo.minSampleShading = 0.0f;
for (int maskIndex = 0; maskIndex < gl::MAX_SAMPLE_MASK_WORDS; ++maskIndex)
{
mMultisampleStateInfo.sampleMask[maskIndex] = 0;
}
mMultisampleStateInfo.alphaToCoverageEnable = 0;
mMultisampleStateInfo.alphaToOneEnable = 0;
mDepthStencilStateInfo.depthTestEnable = 0;
mDepthStencilStateInfo.depthWriteEnable = 1;
mDepthStencilStateInfo.depthCompareOp = static_cast<uint8_t>(VK_COMPARE_OP_LESS);
mDepthStencilStateInfo.depthBoundsTestEnable = 0;
mDepthStencilStateInfo.stencilTestEnable = 0;
mDepthStencilStateInfo.minDepthBounds = 0.0f;
mDepthStencilStateInfo.maxDepthBounds = 0.0f;
mDepthStencilStateInfo.front.failOp = static_cast<uint8_t>(VK_STENCIL_OP_KEEP);
mDepthStencilStateInfo.front.passOp = static_cast<uint8_t>(VK_STENCIL_OP_KEEP);
mDepthStencilStateInfo.front.depthFailOp = static_cast<uint8_t>(VK_STENCIL_OP_KEEP);
mDepthStencilStateInfo.front.compareOp = static_cast<uint8_t>(VK_COMPARE_OP_ALWAYS);
mDepthStencilStateInfo.front.compareMask = static_cast<uint32_t>(-1);
mDepthStencilStateInfo.front.writeMask = static_cast<uint32_t>(-1);
mDepthStencilStateInfo.front.reference = 0;
mDepthStencilStateInfo.back.failOp = static_cast<uint8_t>(VK_STENCIL_OP_KEEP);
mDepthStencilStateInfo.back.passOp = static_cast<uint8_t>(VK_STENCIL_OP_KEEP);
mDepthStencilStateInfo.back.depthFailOp = static_cast<uint8_t>(VK_STENCIL_OP_KEEP);
mDepthStencilStateInfo.back.compareOp = static_cast<uint8_t>(VK_COMPARE_OP_ALWAYS);
mDepthStencilStateInfo.back.compareMask = static_cast<uint32_t>(-1);
mDepthStencilStateInfo.back.writeMask = static_cast<uint32_t>(-1);
mDepthStencilStateInfo.back.reference = 0;
// TODO(jmadill): Blend state/MRT.
PackedColorBlendAttachmentState blendAttachmentState;
blendAttachmentState.blendEnable = 0;
blendAttachmentState.srcColorBlendFactor = static_cast<uint8_t>(VK_BLEND_FACTOR_ONE);
blendAttachmentState.dstColorBlendFactor = static_cast<uint8_t>(VK_BLEND_FACTOR_ONE);
blendAttachmentState.colorBlendOp = static_cast<uint8_t>(VK_BLEND_OP_ADD);
blendAttachmentState.srcAlphaBlendFactor = static_cast<uint8_t>(VK_BLEND_FACTOR_ONE);
blendAttachmentState.dstAlphaBlendFactor = static_cast<uint8_t>(VK_BLEND_FACTOR_ONE);
blendAttachmentState.alphaBlendOp = static_cast<uint8_t>(VK_BLEND_OP_ADD);
blendAttachmentState.colorWriteMask =
static_cast<uint8_t>(VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT);
mColorBlendStateInfo.logicOpEnable = 0;
mColorBlendStateInfo.logicOp = static_cast<uint32_t>(VK_LOGIC_OP_CLEAR);
mColorBlendStateInfo.attachmentCount = 1;
mColorBlendStateInfo.blendConstants[0] = 0.0f;
mColorBlendStateInfo.blendConstants[1] = 0.0f;
mColorBlendStateInfo.blendConstants[2] = 0.0f;
mColorBlendStateInfo.blendConstants[3] = 0.0f;
std::fill(&mColorBlendStateInfo.attachments[0],
&mColorBlendStateInfo.attachments[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS],
blendAttachmentState);
}
Error PipelineDesc::initializePipeline(RendererVk *renderer,
ProgramVk *programVk,
Pipeline *pipelineOut)
{
VkPipelineShaderStageCreateInfo shaderStages[2];
VkPipelineVertexInputStateCreateInfo vertexInputState;
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState;
VkPipelineViewportStateCreateInfo viewportState;
VkPipelineRasterizationStateCreateInfo rasterState;
VkPipelineMultisampleStateCreateInfo multisampleState;
VkPipelineDepthStencilStateCreateInfo depthStencilState;
std::array<VkPipelineColorBlendAttachmentState, gl::IMPLEMENTATION_MAX_DRAW_BUFFERS>
blendAttachmentState;
VkPipelineColorBlendStateCreateInfo blendState;
VkGraphicsPipelineCreateInfo createInfo;
ASSERT(programVk->getVertexModuleSerial() == mShaderStageInfo[0].moduleSerial);
shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
shaderStages[0].pNext = nullptr;
shaderStages[0].flags = 0;
shaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
shaderStages[0].module = programVk->getLinkedVertexModule().getHandle();
shaderStages[0].pName = "main";
shaderStages[0].pSpecializationInfo = nullptr;
ASSERT(programVk->getFragmentModuleSerial() == mShaderStageInfo[1].moduleSerial);
shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
shaderStages[1].pNext = nullptr;
shaderStages[1].flags = 0;
shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
shaderStages[1].module = programVk->getLinkedFragmentModule().getHandle();
shaderStages[1].pName = "main";
shaderStages[1].pSpecializationInfo = nullptr;
// TODO(jmadill): Possibly use different path for ES 3.1 split bindings/attribs.
gl::AttribArray<VkVertexInputBindingDescription> bindingDescs;
gl::AttribArray<VkVertexInputAttributeDescription> attributeDescs;
uint32_t vertexAttribCount = 0;
for (uint32_t attribIndex = 0; attribIndex < gl::MAX_VERTEX_ATTRIBS; ++attribIndex)
{
VkVertexInputBindingDescription &bindingDesc = bindingDescs[attribIndex];
VkVertexInputAttributeDescription &attribDesc = attributeDescs[attribIndex];
const PackedVertexInputBindingDesc &packedBinding = mVertexInputBindings[attribIndex];
const PackedVertexInputAttributeDesc &packedAttrib = mVertexInputAttribs[attribIndex];
// TODO(jmadill): Support for gaps in vertex attribute specification.
if (packedAttrib.format == 0)
continue;
vertexAttribCount = attribIndex + 1;
bindingDesc.binding = attribIndex;
bindingDesc.inputRate = static_cast<VkVertexInputRate>(packedBinding.inputRate);
bindingDesc.stride = static_cast<uint32_t>(packedBinding.stride);
attribDesc.binding = attribIndex;
attribDesc.format = static_cast<VkFormat>(packedAttrib.format);
attribDesc.location = static_cast<uint32_t>(packedAttrib.location);
attribDesc.offset = packedAttrib.offset;
}
// The binding descriptions are filled in at draw time.
vertexInputState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertexInputState.pNext = nullptr;
vertexInputState.flags = 0;
vertexInputState.vertexBindingDescriptionCount = vertexAttribCount;
vertexInputState.pVertexBindingDescriptions = bindingDescs.data();
vertexInputState.vertexAttributeDescriptionCount = vertexAttribCount;
vertexInputState.pVertexAttributeDescriptions = attributeDescs.data();
// Primitive topology is filled in at draw time.
inputAssemblyState.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
inputAssemblyState.pNext = nullptr;
inputAssemblyState.flags = 0;
inputAssemblyState.topology = static_cast<VkPrimitiveTopology>(mInputAssemblyInfo.topology);
inputAssemblyState.primitiveRestartEnable =
static_cast<VkBool32>(mInputAssemblyInfo.primitiveRestartEnable);
// Set initial viewport and scissor state.
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportState.pNext = nullptr;
viewportState.flags = 0;
viewportState.viewportCount = 1;
viewportState.pViewports = &mViewport;
viewportState.scissorCount = 1;
viewportState.pScissors = &mScissor;
// Rasterizer state.
rasterState.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterState.pNext = nullptr;
rasterState.flags = 0;
rasterState.depthClampEnable = static_cast<VkBool32>(mRasterizationStateInfo.depthClampEnable);
rasterState.rasterizerDiscardEnable =
static_cast<VkBool32>(mRasterizationStateInfo.rasterizationDiscardEnable);
rasterState.polygonMode = static_cast<VkPolygonMode>(mRasterizationStateInfo.polygonMode);
rasterState.cullMode = static_cast<VkCullModeFlags>(mRasterizationStateInfo.cullMode);
rasterState.frontFace = static_cast<VkFrontFace>(mRasterizationStateInfo.frontFace);
rasterState.depthBiasEnable = static_cast<VkBool32>(mRasterizationStateInfo.depthBiasEnable);
rasterState.depthBiasConstantFactor = mRasterizationStateInfo.depthBiasConstantFactor;
rasterState.depthBiasClamp = mRasterizationStateInfo.depthBiasClamp;
rasterState.depthBiasSlopeFactor = mRasterizationStateInfo.depthBiasSlopeFactor;
rasterState.lineWidth = mRasterizationStateInfo.lineWidth;
// Multisample state.
multisampleState.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampleState.pNext = nullptr;
multisampleState.flags = 0;
multisampleState.rasterizationSamples =
ConvertSamples(mMultisampleStateInfo.rasterizationSamples);
multisampleState.sampleShadingEnable =
static_cast<VkBool32>(mMultisampleStateInfo.sampleShadingEnable);
multisampleState.minSampleShading = mMultisampleStateInfo.minSampleShading;
// TODO(jmadill): sample masks
multisampleState.pSampleMask = nullptr;
multisampleState.alphaToCoverageEnable =
static_cast<VkBool32>(mMultisampleStateInfo.alphaToCoverageEnable);
multisampleState.alphaToOneEnable =
static_cast<VkBool32>(mMultisampleStateInfo.alphaToOneEnable);
// Depth/stencil state.
depthStencilState.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
depthStencilState.pNext = nullptr;
depthStencilState.flags = 0;
depthStencilState.depthTestEnable =
static_cast<VkBool32>(mDepthStencilStateInfo.depthTestEnable);
depthStencilState.depthWriteEnable =
static_cast<VkBool32>(mDepthStencilStateInfo.depthWriteEnable);
depthStencilState.depthCompareOp =
static_cast<VkCompareOp>(mDepthStencilStateInfo.depthCompareOp);
depthStencilState.depthBoundsTestEnable =
static_cast<VkBool32>(mDepthStencilStateInfo.depthBoundsTestEnable);
depthStencilState.stencilTestEnable =
static_cast<VkBool32>(mDepthStencilStateInfo.stencilTestEnable);
UnpackStencilState(mDepthStencilStateInfo.front, &depthStencilState.front);
UnpackStencilState(mDepthStencilStateInfo.back, &depthStencilState.back);
depthStencilState.minDepthBounds = mDepthStencilStateInfo.minDepthBounds;
depthStencilState.maxDepthBounds = mDepthStencilStateInfo.maxDepthBounds;
blendState.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
blendState.pNext = 0;
blendState.flags = 0;
blendState.logicOpEnable = static_cast<VkBool32>(mColorBlendStateInfo.logicOpEnable);
blendState.logicOp = static_cast<VkLogicOp>(mColorBlendStateInfo.logicOp);
blendState.attachmentCount = mColorBlendStateInfo.attachmentCount;
blendState.pAttachments = blendAttachmentState.data();
for (int i = 0; i < 4; i++)
{
blendState.blendConstants[i] = mColorBlendStateInfo.blendConstants[i];
}
for (uint32_t colorIndex = 0; colorIndex < blendState.attachmentCount; ++colorIndex)
{
UnpackBlendAttachmentState(mColorBlendStateInfo.attachments[colorIndex],
&blendAttachmentState[colorIndex]);
}
// TODO(jmadill): Dynamic state.
// Pull in a compatible RenderPass.
RenderPass *compatibleRenderPass = nullptr;
ANGLE_TRY(renderer->getCompatibleRenderPass(mRenderPassDesc, &compatibleRenderPass));
createInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.stageCount = 2;
createInfo.pStages = shaderStages;
createInfo.pVertexInputState = &vertexInputState;
createInfo.pInputAssemblyState = &inputAssemblyState;
createInfo.pTessellationState = nullptr;
createInfo.pViewportState = &viewportState;
createInfo.pRasterizationState = &rasterState;
createInfo.pMultisampleState = &multisampleState;
createInfo.pDepthStencilState = &depthStencilState;
createInfo.pColorBlendState = &blendState;
createInfo.pDynamicState = nullptr;
createInfo.layout = renderer->getGraphicsPipelineLayout().getHandle();
createInfo.renderPass = compatibleRenderPass->getHandle();
createInfo.subpass = 0;
createInfo.basePipelineHandle = VK_NULL_HANDLE;
createInfo.basePipelineIndex = 0;
ANGLE_TRY(pipelineOut->initGraphics(renderer->getDevice(), createInfo));
return NoError();
}
void PipelineDesc::updateShaders(ProgramVk *programVk)
{
ASSERT(programVk->getVertexModuleSerial() < std::numeric_limits<uint32_t>::max());
mShaderStageInfo[0].moduleSerial =
static_cast<uint32_t>(programVk->getVertexModuleSerial().getValue());
ASSERT(programVk->getFragmentModuleSerial() < std::numeric_limits<uint32_t>::max());
mShaderStageInfo[1].moduleSerial =
static_cast<uint32_t>(programVk->getFragmentModuleSerial().getValue());
}
void PipelineDesc::updateViewport(const gl::Rectangle &viewport, float nearPlane, float farPlane)
{
mViewport.x = static_cast<float>(viewport.x);
mViewport.y = static_cast<float>(viewport.y);
mViewport.width = static_cast<float>(viewport.width);
mViewport.height = static_cast<float>(viewport.height);
mViewport.minDepth = nearPlane;
mViewport.maxDepth = farPlane;
// TODO(jmadill): Scissor.
mScissor.offset.x = viewport.x;
mScissor.offset.y = viewport.y;
mScissor.extent.width = viewport.width;
mScissor.extent.height = viewport.height;
}
void PipelineDesc::resetVertexInputState()
{
memset(&mVertexInputBindings, 0, sizeof(VertexInputBindings));
memset(&mVertexInputAttribs, 0, sizeof(VertexInputAttributes));
}
void PipelineDesc::updateVertexInputInfo(uint32_t attribIndex,
const gl::VertexBinding &binding,
const gl::VertexAttribute &attrib)
{
PackedVertexInputBindingDesc &bindingDesc = mVertexInputBindings[attribIndex];
size_t attribSize = gl::ComputeVertexAttributeTypeSize(attrib);
ASSERT(attribSize <= std::numeric_limits<uint16_t>::max());
bindingDesc.stride = static_cast<uint16_t>(attribSize);
bindingDesc.inputRate = static_cast<uint16_t>(
binding.getDivisor() > 0 ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX);
gl::VertexFormatType vertexFormatType = gl::GetVertexFormatType(attrib);
VkFormat vkFormat = vk::GetNativeVertexFormat(vertexFormatType);
ASSERT(vkFormat <= std::numeric_limits<uint16_t>::max());
PackedVertexInputAttributeDesc &attribDesc = mVertexInputAttribs[attribIndex];
attribDesc.format = static_cast<uint16_t>(vkFormat);
attribDesc.location = static_cast<uint16_t>(attribIndex);
attribDesc.offset = static_cast<uint32_t>(ComputeVertexAttributeOffset(attrib, binding));
}
void PipelineDesc::updateTopology(GLenum drawMode)
{
mInputAssemblyInfo.topology = static_cast<uint32_t>(gl_vk::GetPrimitiveTopology(drawMode));
}
void PipelineDesc::updateCullMode(const gl::RasterizerState &rasterState)
{
mRasterizationStateInfo.cullMode = static_cast<uint16_t>(gl_vk::GetCullMode(rasterState));
}
void PipelineDesc::updateFrontFace(const gl::RasterizerState &rasterState)
{
mRasterizationStateInfo.frontFace =
static_cast<uint16_t>(gl_vk::GetFrontFace(rasterState.frontFace));
}
void PipelineDesc::updateLineWidth(float lineWidth)
{
mRasterizationStateInfo.lineWidth = lineWidth;
}
void PipelineDesc::updateRenderPassDesc(const RenderPassDesc &renderPassDesc)
{
mRenderPassDesc = renderPassDesc;
}
// AttachmentOpsArray implementation.
AttachmentOpsArray::AttachmentOpsArray()
{
memset(&mOps, 0, sizeof(PackedAttachmentOpsDesc) * mOps.size());
}
AttachmentOpsArray::~AttachmentOpsArray()
{
}
AttachmentOpsArray::AttachmentOpsArray(const AttachmentOpsArray &other)
{
memcpy(&mOps, &other.mOps, sizeof(PackedAttachmentOpsDesc) * mOps.size());
}
AttachmentOpsArray &AttachmentOpsArray::operator=(const AttachmentOpsArray &other)
{
memcpy(&mOps, &other.mOps, sizeof(PackedAttachmentOpsDesc) * mOps.size());
return *this;
}
const PackedAttachmentOpsDesc &AttachmentOpsArray::operator[](size_t index) const
{
return mOps[index];
}
PackedAttachmentOpsDesc &AttachmentOpsArray::operator[](size_t index)
{
return mOps[index];
}
void AttachmentOpsArray::initDummyOp(size_t index, VkImageLayout finalLayout)
{
PackedAttachmentOpsDesc &ops = mOps[index];
ops.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
ops.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
ops.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
ops.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
ops.initialLayout = static_cast<uint16_t>(VK_IMAGE_LAYOUT_UNDEFINED);
ops.finalLayout = static_cast<uint16_t>(finalLayout);
}
size_t AttachmentOpsArray::hash() const
{
return angle::ComputeGenericHash(mOps);
}
bool operator==(const AttachmentOpsArray &lhs, const AttachmentOpsArray &rhs)
{
return (memcmp(&lhs, &rhs, sizeof(AttachmentOpsArray)) == 0);
}
} // namespace vk
// RenderPassCache implementation.
RenderPassCache::RenderPassCache()
{
}
RenderPassCache::~RenderPassCache()
{
ASSERT(mPayload.empty());
}
void RenderPassCache::destroy(VkDevice device)
{
for (auto &outerIt : mPayload)
{
for (auto &innerIt : outerIt.second)
{
innerIt.second.get().destroy(device);
}
}
mPayload.clear();
}
vk::Error RenderPassCache::getCompatibleRenderPass(VkDevice device,
Serial serial,
const vk::RenderPassDesc &desc,
vk::RenderPass **renderPassOut)
{
auto outerIt = mPayload.find(desc);
if (outerIt != mPayload.end())
{
InnerCache &innerCache = outerIt->second;
ASSERT(!innerCache.empty());
// Find the first element and return it.
*renderPassOut = &innerCache.begin()->second.get();
return vk::NoError();
}
// Insert some dummy attachment ops.
// TODO(jmadill): Pre-populate the cache in the Renderer so we rarely miss here.
vk::AttachmentOpsArray ops;
for (uint32_t colorIndex = 0; colorIndex < desc.colorAttachmentCount(); ++colorIndex)
{
ops.initDummyOp(colorIndex, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
}
if (desc.depthStencilAttachmentCount() > 0)
{
ops.initDummyOp(desc.colorAttachmentCount(),
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
}
return getRenderPassWithOps(device, serial, desc, ops, renderPassOut);
}
vk::Error RenderPassCache::getRenderPassWithOps(VkDevice device,
Serial serial,
const vk::RenderPassDesc &desc,
const vk::AttachmentOpsArray &attachmentOps,
vk::RenderPass **renderPassOut)
{
auto outerIt = mPayload.find(desc);
if (outerIt != mPayload.end())
{
InnerCache &innerCache = outerIt->second;
auto innerIt = innerCache.find(attachmentOps);
if (innerIt != innerCache.end())
{
// Update the serial before we return.
// TODO(jmadill): Could possibly use an MRU cache here.
innerIt->second.updateSerial(serial);
*renderPassOut = &innerIt->second.get();
return vk::NoError();
}
}
else
{
auto emplaceResult = mPayload.emplace(desc, InnerCache());
outerIt = emplaceResult.first;
}
vk::RenderPass newRenderPass;
ANGLE_TRY(vk::InitializeRenderPassFromDesc(device, desc, attachmentOps, &newRenderPass));
vk::RenderPassAndSerial withSerial(std::move(newRenderPass), serial);
InnerCache &innerCache = outerIt->second;
auto insertPos = innerCache.emplace(attachmentOps, std::move(withSerial));
*renderPassOut = &insertPos.first->second.get();
// TODO(jmadill): Trim cache, and pre-populate with the most common RPs on startup.
return vk::NoError();
}
} // namespace rx