Commit f2f6d379 by Jamie Madill Committed by Commit Bot

Vulkan: Add PipelineDesc.

The PipelineDesc class is a 512-byte packed description of the entire Vulkan pipeline state. It uses the alignas keyword and some static asserts to verify that the structures are packed. This ensures that when ANGLE uses MurmurHash to hash the entire struct, and memcmp to check for identity, that there are no garbage padding bits. This CL does not implement the Pipeline cache, but it will help, since now we have a packed type that can be used as the key to a hash map. Bug: angleproject:2163 Change-Id: I16efa927f08d30d89a9c4c8943edd211c6878ac8 Reviewed-on: https://chromium-review.googlesource.com/829893 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarFrank Henigman <fjhenigman@chromium.org>
parent b0accd45
......@@ -71,6 +71,10 @@ class Serial final
{
return mValue != kInvalid && mValue == other.mValue;
}
constexpr bool operator==(uint32_t value) const
{
return mValue != kInvalid && mValue == static_cast<uint64_t>(value);
}
constexpr bool operator!=(const Serial &other) const
{
return mValue == kInvalid || mValue != other.mValue;
......@@ -80,6 +84,11 @@ class Serial final
constexpr bool operator<(const Serial &other) const { return mValue < other.mValue; }
constexpr bool operator<=(const Serial &other) const { return mValue <= other.mValue; }
constexpr bool operator<(uint32_t value) const { return mValue < static_cast<uint64_t>(value); }
// Useful for serialization.
constexpr uint64_t getValue() const { return mValue; }
private:
friend class SerialFactory;
constexpr explicit Serial(uint64_t value) : mValue(value) {}
......
......@@ -69,137 +69,6 @@ ContextVk::ContextVk(const gl::ContextState &state, RendererVk *renderer)
mVertexArrayDirty(false),
mTexturesDirty(false)
{
// The module handle is filled out at draw time.
mCurrentShaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
mCurrentShaderStages[0].pNext = nullptr;
mCurrentShaderStages[0].flags = 0;
mCurrentShaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
mCurrentShaderStages[0].module = VK_NULL_HANDLE;
mCurrentShaderStages[0].pName = "main";
mCurrentShaderStages[0].pSpecializationInfo = nullptr;
mCurrentShaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
mCurrentShaderStages[1].pNext = nullptr;
mCurrentShaderStages[1].flags = 0;
mCurrentShaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
mCurrentShaderStages[1].module = VK_NULL_HANDLE;
mCurrentShaderStages[1].pName = "main";
mCurrentShaderStages[1].pSpecializationInfo = nullptr;
// The binding descriptions are filled in at draw time.
mCurrentVertexInputState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
mCurrentVertexInputState.pNext = nullptr;
mCurrentVertexInputState.flags = 0;
mCurrentVertexInputState.vertexBindingDescriptionCount = 0;
mCurrentVertexInputState.pVertexBindingDescriptions = nullptr;
mCurrentVertexInputState.vertexAttributeDescriptionCount = 0;
mCurrentVertexInputState.pVertexAttributeDescriptions = nullptr;
// Primitive topology is filled in at draw time.
mCurrentInputAssemblyState.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
mCurrentInputAssemblyState.pNext = nullptr;
mCurrentInputAssemblyState.flags = 0;
mCurrentInputAssemblyState.topology = gl_vk::GetPrimitiveTopology(mCurrentDrawMode);
mCurrentInputAssemblyState.primitiveRestartEnable = VK_FALSE;
// Set initial viewport and scissor state.
mCurrentViewportVk.x = 0.0f;
mCurrentViewportVk.y = 0.0f;
mCurrentViewportVk.width = 0.0f;
mCurrentViewportVk.height = 0.0f;
mCurrentViewportVk.minDepth = 0.0f;
mCurrentViewportVk.maxDepth = 1.0f;
mCurrentScissorVk.offset.x = 0;
mCurrentScissorVk.offset.y = 0;
mCurrentScissorVk.extent.width = 0u;
mCurrentScissorVk.extent.height = 0u;
mCurrentViewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
mCurrentViewportState.pNext = nullptr;
mCurrentViewportState.flags = 0;
mCurrentViewportState.viewportCount = 1;
mCurrentViewportState.pViewports = &mCurrentViewportVk;
mCurrentViewportState.scissorCount = 1;
mCurrentViewportState.pScissors = &mCurrentScissorVk;
// Set initial rasterizer state.
// TODO(jmadill): Extra rasterizer state features.
mCurrentRasterState.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
mCurrentRasterState.pNext = nullptr;
mCurrentRasterState.flags = 0;
mCurrentRasterState.depthClampEnable = VK_FALSE;
mCurrentRasterState.rasterizerDiscardEnable = VK_FALSE;
mCurrentRasterState.polygonMode = VK_POLYGON_MODE_FILL;
mCurrentRasterState.cullMode = VK_CULL_MODE_NONE;
mCurrentRasterState.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
mCurrentRasterState.depthBiasEnable = VK_FALSE;
mCurrentRasterState.depthBiasConstantFactor = 0.0f;
mCurrentRasterState.depthBiasClamp = 0.0f;
mCurrentRasterState.depthBiasSlopeFactor = 0.0f;
mCurrentRasterState.lineWidth = 1.0f;
// Initialize a dummy multisample state.
// TODO(jmadill): Multisample state.
mCurrentMultisampleState.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
mCurrentMultisampleState.pNext = nullptr;
mCurrentMultisampleState.flags = 0;
mCurrentMultisampleState.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
mCurrentMultisampleState.sampleShadingEnable = VK_FALSE;
mCurrentMultisampleState.minSampleShading = 0.0f;
mCurrentMultisampleState.pSampleMask = nullptr;
mCurrentMultisampleState.alphaToCoverageEnable = VK_FALSE;
mCurrentMultisampleState.alphaToOneEnable = VK_FALSE;
// TODO(jmadill): Depth/stencil state.
// Initialize a dummy MRT blend state.
// TODO(jmadill): Blend state/MRT.
mCurrentBlendAttachmentState.blendEnable = VK_FALSE;
mCurrentBlendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
mCurrentBlendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE;
mCurrentBlendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD;
mCurrentBlendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
mCurrentBlendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
mCurrentBlendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD;
mCurrentBlendAttachmentState.colorWriteMask =
(VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT |
VK_COLOR_COMPONENT_A_BIT);
mCurrentBlendState.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
mCurrentBlendState.pNext = 0;
mCurrentBlendState.flags = 0;
mCurrentBlendState.logicOpEnable = VK_FALSE;
mCurrentBlendState.logicOp = VK_LOGIC_OP_CLEAR;
mCurrentBlendState.attachmentCount = 1;
mCurrentBlendState.pAttachments = &mCurrentBlendAttachmentState;
mCurrentBlendState.blendConstants[0] = 0.0f;
mCurrentBlendState.blendConstants[1] = 0.0f;
mCurrentBlendState.blendConstants[2] = 0.0f;
mCurrentBlendState.blendConstants[3] = 0.0f;
// TODO(jmadill): Dynamic state.
// The layout and renderpass are filled out at draw time.
mCurrentPipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
mCurrentPipelineInfo.pNext = nullptr;
mCurrentPipelineInfo.flags = 0;
mCurrentPipelineInfo.stageCount = 2;
mCurrentPipelineInfo.pStages = mCurrentShaderStages;
mCurrentPipelineInfo.pVertexInputState = &mCurrentVertexInputState;
mCurrentPipelineInfo.pInputAssemblyState = &mCurrentInputAssemblyState;
mCurrentPipelineInfo.pTessellationState = nullptr;
mCurrentPipelineInfo.pViewportState = &mCurrentViewportState;
mCurrentPipelineInfo.pRasterizationState = &mCurrentRasterState;
mCurrentPipelineInfo.pMultisampleState = &mCurrentMultisampleState;
mCurrentPipelineInfo.pDepthStencilState = nullptr;
mCurrentPipelineInfo.pColorBlendState = &mCurrentBlendState;
mCurrentPipelineInfo.pDynamicState = nullptr;
mCurrentPipelineInfo.layout = VK_NULL_HANDLE;
mCurrentPipelineInfo.renderPass = VK_NULL_HANDLE;
mCurrentPipelineInfo.subpass = 0;
mCurrentPipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
mCurrentPipelineInfo.basePipelineIndex = 0;
}
ContextVk::~ContextVk()
......@@ -238,6 +107,9 @@ gl::Error ContextVk::initialize()
ANGLE_TRY(mDescriptorPool.init(device, descriptorPoolInfo));
mPipelineDesc.reset(new vk::PipelineDesc());
mPipelineDesc->initDefaults();
return gl::NoError();
}
......@@ -257,42 +129,22 @@ gl::Error ContextVk::initPipeline(const gl::Context *context)
{
ASSERT(!mCurrentPipeline.valid());
VkDevice device = mRenderer->getDevice();
const auto &state = mState.getState();
const gl::VertexArray *vao = state.getVertexArray();
const gl::Framebuffer *drawFBO = state.getDrawFramebuffer();
FramebufferVk *vkFBO = vk::GetImpl(drawFBO);
VertexArrayVk *vkVAO = vk::GetImpl(vao);
const gl::State &state = mState.getState();
VertexArrayVk *vertexArrayVk = vk::GetImpl(state.getVertexArray());
FramebufferVk *framebufferVk = vk::GetImpl(state.getDrawFramebuffer());
ProgramVk *programVk = vk::GetImpl(state.getProgram());
// Ensure the topology of the pipeline description is updated.
mPipelineDesc->updateTopology(mCurrentDrawMode);
// Ensure the attribs and bindings are updated.
vkVAO->updateVertexDescriptions(context);
vertexArrayVk->updateVertexDescriptions(context, mPipelineDesc.get());
const auto &vertexBindings = vkVAO->getVertexBindingDescs();
const auto &vertexAttribs = vkVAO->getVertexAttribDescs();
// Ensure that the RenderPass description is updated.
mPipelineDesc->updateRenderPassDesc(framebufferVk->getRenderPassDesc(context));
// TODO(jmadill): Validate with ASSERT against physical device limits/caps?
mCurrentVertexInputState.vertexBindingDescriptionCount =
static_cast<uint32_t>(vertexBindings.size());
mCurrentVertexInputState.pVertexBindingDescriptions = vertexBindings.data();
mCurrentVertexInputState.vertexAttributeDescriptionCount =
static_cast<uint32_t>(vertexAttribs.size());
mCurrentVertexInputState.pVertexAttributeDescriptions = vertexAttribs.data();
mCurrentInputAssemblyState.topology = gl_vk::GetPrimitiveTopology(mCurrentDrawMode);
const vk::RenderPassDesc &desc = vkFBO->getRenderPassDesc(context);
vk::RenderPass *renderPass = nullptr;
ANGLE_TRY(mRenderer->getCompatibleRenderPass(desc, &renderPass));
ASSERT(renderPass && renderPass->valid());
const vk::PipelineLayout &pipelineLayout = mRenderer->getGraphicsPipelineLayout();
ASSERT(pipelineLayout.valid());
mCurrentPipelineInfo.layout = pipelineLayout.getHandle();
mCurrentPipelineInfo.renderPass = renderPass->getHandle();
ANGLE_TRY(mCurrentPipeline.initGraphics(device, mCurrentPipelineInfo));
ANGLE_TRY(mPipelineDesc->initializePipeline(mRenderer, programVk, &mCurrentPipeline));
return gl::NoError();
}
......@@ -569,22 +421,9 @@ void ContextVk::syncState(const gl::Context *context, const gl::State::DirtyBits
WARN() << "DIRTY_BIT_SCISSOR unimplemented";
break;
case gl::State::DIRTY_BIT_VIEWPORT:
{
const gl::Rectangle &viewportGL = glState.getViewport();
mCurrentViewportVk.x = static_cast<float>(viewportGL.x);
mCurrentViewportVk.y = static_cast<float>(viewportGL.y);
mCurrentViewportVk.width = static_cast<float>(viewportGL.width);
mCurrentViewportVk.height = static_cast<float>(viewportGL.height);
mCurrentViewportVk.minDepth = glState.getNearPlane();
mCurrentViewportVk.maxDepth = glState.getFarPlane();
// TODO(jmadill): Scissor.
mCurrentScissorVk.offset.x = viewportGL.x;
mCurrentScissorVk.offset.y = viewportGL.y;
mCurrentScissorVk.extent.width = viewportGL.width;
mCurrentScissorVk.extent.height = viewportGL.height;
mPipelineDesc->updateViewport(glState.getViewport(), glState.getNearPlane(),
glState.getFarPlane());
break;
}
case gl::State::DIRTY_BIT_DEPTH_RANGE:
WARN() << "DIRTY_BIT_DEPTH_RANGE unimplemented";
break;
......@@ -650,11 +489,10 @@ void ContextVk::syncState(const gl::Context *context, const gl::State::DirtyBits
break;
case gl::State::DIRTY_BIT_CULL_FACE_ENABLED:
case gl::State::DIRTY_BIT_CULL_FACE:
mCurrentRasterState.cullMode = gl_vk::GetCullMode(glState.getRasterizerState());
mPipelineDesc->updateCullMode(glState.getRasterizerState());
break;
case gl::State::DIRTY_BIT_FRONT_FACE:
mCurrentRasterState.frontFace =
gl_vk::GetFrontFace(glState.getRasterizerState().frontFace);
mPipelineDesc->updateFrontFace(glState.getRasterizerState());
break;
case gl::State::DIRTY_BIT_POLYGON_OFFSET_FILL_ENABLED:
WARN() << "DIRTY_BIT_POLYGON_OFFSET_FILL_ENABLED unimplemented";
......@@ -666,7 +504,7 @@ void ContextVk::syncState(const gl::Context *context, const gl::State::DirtyBits
WARN() << "DIRTY_BIT_RASTERIZER_DISCARD_ENABLED unimplemented";
break;
case gl::State::DIRTY_BIT_LINE_WIDTH:
mCurrentRasterState.lineWidth = glState.getLineWidth();
mPipelineDesc->updateLineWidth(glState.getLineWidth());
break;
case gl::State::DIRTY_BIT_PRIMITIVE_RESTART_ENABLED:
WARN() << "DIRTY_BIT_PRIMITIVE_RESTART_ENABLED unimplemented";
......@@ -711,8 +549,12 @@ void ContextVk::syncState(const gl::Context *context, const gl::State::DirtyBits
WARN() << "DIRTY_BIT_RENDERBUFFER_BINDING unimplemented";
break;
case gl::State::DIRTY_BIT_VERTEX_ARRAY_BINDING:
{
VertexArrayVk *vertexArrayVk = vk::GetImpl(glState.getVertexArray());
vertexArrayVk->invalidateVertexDescriptions();
mVertexArrayDirty = true;
break;
}
case gl::State::DIRTY_BIT_DRAW_INDIRECT_BUFFER_BINDING:
WARN() << "DIRTY_BIT_DRAW_INDIRECT_BUFFER_BINDING unimplemented";
break;
......@@ -724,14 +566,12 @@ void ContextVk::syncState(const gl::Context *context, const gl::State::DirtyBits
break;
case gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE:
{
// { vertex, fragment }
ProgramVk *programVk = vk::GetImpl(glState.getProgram());
mCurrentShaderStages[0].module = programVk->getLinkedVertexModule().getHandle();
mCurrentShaderStages[1].module = programVk->getLinkedFragmentModule().getHandle();
mPipelineDesc->updateShaders(programVk);
// Also invalidate the vertex descriptions cache in the Vertex Array.
VertexArrayVk *vaoVk = vk::GetImpl(glState.getVertexArray());
vaoVk->invalidateVertexDescriptions();
VertexArrayVk *vertexArrayVk = vk::GetImpl(glState.getVertexArray());
vertexArrayVk->invalidateVertexDescriptions();
dirtyTextures = true;
break;
......
......@@ -170,21 +170,9 @@ class ContextVk : public ContextImpl, public ResourceVk
vk::Pipeline mCurrentPipeline;
GLenum mCurrentDrawMode;
// Keep CreateInfo structures cached so that we can quickly update them when creating
// updated pipelines. When we move to a pipeline cache, we will want to use a more compact
// structure that we can use to query the pipeline cache in the Renderer.
// TODO(jmadill): Update this when we move to a pipeline cache.
VkPipelineShaderStageCreateInfo mCurrentShaderStages[2];
VkPipelineVertexInputStateCreateInfo mCurrentVertexInputState;
VkPipelineInputAssemblyStateCreateInfo mCurrentInputAssemblyState;
VkViewport mCurrentViewportVk;
VkRect2D mCurrentScissorVk;
VkPipelineViewportStateCreateInfo mCurrentViewportState;
VkPipelineRasterizationStateCreateInfo mCurrentRasterState;
VkPipelineMultisampleStateCreateInfo mCurrentMultisampleState;
VkPipelineColorBlendAttachmentState mCurrentBlendAttachmentState;
VkPipelineColorBlendStateCreateInfo mCurrentBlendState;
VkGraphicsPipelineCreateInfo mCurrentPipelineInfo;
// Keep a cached pipeline description structure that can be used to query the pipeline cache.
// Kept in a pointer so allocations can be aligned, and structs can be portably packed.
std::unique_ptr<vk::PipelineDesc> mPipelineDesc;
// The descriptor pool is externally sychronized, so cannot be accessed from different threads
// simulataneously. Hence, we keep it in the ContextVk instead of the RendererVk.
......
......@@ -167,6 +167,8 @@ void ProgramVk::reset(VkDevice device)
mLinkedFragmentModule.destroy(device);
mLinkedVertexModule.destroy(device);
mVertexModuleSerial = Serial();
mFragmentModuleSerial = Serial();
// Descriptor Sets are pool allocated, so do not need to be explicitly freed.
mDescriptorSets.clear();
......@@ -228,6 +230,7 @@ gl::LinkResult ProgramVk::link(const gl::Context *glContext,
vertexShaderInfo.pCode = vertexCode.data();
ANGLE_TRY(mLinkedVertexModule.init(device, vertexShaderInfo));
mVertexModuleSerial = renderer->issueProgramSerial();
}
{
......@@ -239,6 +242,7 @@ gl::LinkResult ProgramVk::link(const gl::Context *glContext,
fragmentShaderInfo.pCode = fragmentCode.data();
ANGLE_TRY(mLinkedFragmentModule.init(device, fragmentShaderInfo));
mFragmentModuleSerial = renderer->issueProgramSerial();
}
ANGLE_TRY(initDescriptorSets(contextVk));
......@@ -546,12 +550,22 @@ const vk::ShaderModule &ProgramVk::getLinkedVertexModule() const
return mLinkedVertexModule;
}
Serial ProgramVk::getVertexModuleSerial() const
{
return mVertexModuleSerial;
}
const vk::ShaderModule &ProgramVk::getLinkedFragmentModule() const
{
ASSERT(mLinkedFragmentModule.getHandle() != VK_NULL_HANDLE);
return mLinkedFragmentModule;
}
Serial ProgramVk::getFragmentModuleSerial() const
{
return mFragmentModuleSerial;
}
vk::Error ProgramVk::initDescriptorSets(ContextVk *contextVk)
{
ASSERT(mDescriptorSets.empty());
......
......@@ -100,7 +100,9 @@ class ProgramVk : public ProgramImpl
const GLfloat *coeffs) override;
const vk::ShaderModule &getLinkedVertexModule() const;
Serial getVertexModuleSerial() const;
const vk::ShaderModule &getLinkedFragmentModule() const;
Serial getFragmentModuleSerial() const;
vk::Error updateUniforms(ContextVk *contextVk);
......@@ -127,7 +129,9 @@ class ProgramVk : public ProgramImpl
void setUniformImpl(GLint location, GLsizei count, const T *v, GLenum entryPointType);
vk::ShaderModule mLinkedVertexModule;
Serial mVertexModuleSerial;
vk::ShaderModule mLinkedFragmentModule;
Serial mFragmentModuleSerial;
// State for the default uniform blocks.
struct DefaultUniformBlock final : private angle::NonCopyable
......
......@@ -1070,4 +1070,10 @@ vk::Error RendererVk::initGraphicsPipelineLayout()
return vk::NoError();
}
Serial RendererVk::issueProgramSerial()
{
return mProgramSerialFactory.generate();
}
} // namespace rx
......@@ -147,6 +147,9 @@ class RendererVk : angle::NonCopyable
const vk::PipelineLayout &getGraphicsPipelineLayout() const;
const std::vector<vk::DescriptorSetLayout> &getGraphicsDescriptorSetLayouts() const;
// Issues a new serial for linked shader modules. Used in the pipeline cache.
Serial issueProgramSerial();
private:
vk::Error initializeDevice(uint32_t queueFamilyIndex);
void ensureCapsInitialized() const;
......@@ -179,6 +182,7 @@ class RendererVk : angle::NonCopyable
vk::CommandPool mCommandPool;
GlslangWrapper *mGlslangWrapper;
SerialFactory mQueueSerialFactory;
SerialFactory mProgramSerialFactory;
Serial mLastCompletedQueueSerial;
Serial mCurrentQueueSerial;
......
......@@ -29,8 +29,6 @@ VertexArrayVk::VertexArrayVk(const gl::VertexArrayState &state)
{
mCurrentArrayBufferHandles.fill(VK_NULL_HANDLE);
mCurrentArrayBufferResources.fill(nullptr);
mCurrentVertexBindingDescs.reserve(state.getMaxAttribs());
mCurrentVertexAttribDescs.reserve(state.getMaxAttribs());
}
VertexArrayVk::~VertexArrayVk()
......@@ -131,11 +129,10 @@ void VertexArrayVk::updateDrawDependencies(vk::CommandBufferNode *readNode,
void VertexArrayVk::invalidateVertexDescriptions()
{
mCurrentVertexDescsValid = false;
mCurrentVertexBindingDescs.clear();
mCurrentVertexAttribDescs.clear();
}
void VertexArrayVk::updateVertexDescriptions(const gl::Context *context)
void VertexArrayVk::updateVertexDescriptions(const gl::Context *context,
vk::PipelineDesc *pipelineDesc)
{
if (mCurrentVertexDescsValid)
{
......@@ -147,29 +144,16 @@ void VertexArrayVk::updateVertexDescriptions(const gl::Context *context)
const gl::Program *programGL = context->getGLState().getProgram();
pipelineDesc->resetVertexInputState();
for (auto attribIndex : programGL->getActiveAttribLocationsMask())
{
const auto &attrib = attribs[attribIndex];
const auto &binding = bindings[attrib.bindingIndex];
if (attrib.enabled)
{
VkVertexInputBindingDescription bindingDesc;
bindingDesc.binding = static_cast<uint32_t>(mCurrentVertexBindingDescs.size());
bindingDesc.stride = static_cast<uint32_t>(gl::ComputeVertexAttributeTypeSize(attrib));
bindingDesc.inputRate = (binding.getDivisor() > 0 ? VK_VERTEX_INPUT_RATE_INSTANCE
: VK_VERTEX_INPUT_RATE_VERTEX);
gl::VertexFormatType vertexFormatType = gl::GetVertexFormatType(attrib);
VkVertexInputAttributeDescription attribDesc;
attribDesc.binding = bindingDesc.binding;
attribDesc.format = vk::GetNativeVertexFormat(vertexFormatType);
attribDesc.location = static_cast<uint32_t>(attribIndex);
attribDesc.offset =
static_cast<uint32_t>(ComputeVertexAttributeOffset(attrib, binding));
mCurrentVertexBindingDescs.push_back(bindingDesc);
mCurrentVertexAttribDescs.push_back(attribDesc);
pipelineDesc->updateVertexInputInfo(static_cast<uint32_t>(attribIndex), binding,
attrib);
}
else
{
......@@ -180,14 +164,4 @@ void VertexArrayVk::updateVertexDescriptions(const gl::Context *context)
mCurrentVertexDescsValid = true;
}
const std::vector<VkVertexInputBindingDescription> &VertexArrayVk::getVertexBindingDescs() const
{
return mCurrentVertexBindingDescs;
}
const std::vector<VkVertexInputAttributeDescription> &VertexArrayVk::getVertexAttribDescs() const
{
return mCurrentVertexAttribDescs;
}
} // namespace rx
......@@ -36,10 +36,7 @@ class VertexArrayVk : public VertexArrayImpl
DrawType drawType);
void invalidateVertexDescriptions();
void updateVertexDescriptions(const gl::Context *context);
const std::vector<VkVertexInputBindingDescription> &getVertexBindingDescs() const;
const std::vector<VkVertexInputAttributeDescription> &getVertexAttribDescs() const;
void updateVertexDescriptions(const gl::Context *context, vk::PipelineDesc *pipelineDesc);
private:
gl::AttribArray<VkBuffer> mCurrentArrayBufferHandles;
......@@ -49,8 +46,6 @@ class VertexArrayVk : public VertexArrayImpl
// Keep a cache of binding and attribute descriptions for easy pipeline updates.
// TODO(jmadill): Update this when we support pipeline caching.
bool mCurrentVertexDescsValid;
std::vector<VkVertexInputBindingDescription> mCurrentVertexBindingDescs;
std::vector<VkVertexInputAttributeDescription> mCurrentVertexAttribDescs;
};
} // namespace rx
......
......@@ -7,8 +7,9 @@
// Helper functions for the Vulkan Renderer.
//
#include "renderervk_utils.h"
#include "libANGLE/renderer/vulkan/renderervk_utils.h"
#include "common/aligned_memory.h"
#include "libANGLE/Context.h"
#include "libANGLE/SizedMRUCache.h"
#include "libANGLE/renderer/vulkan/CommandBufferNode.h"
......@@ -16,6 +17,9 @@
#include "libANGLE/renderer/vulkan/RenderTargetVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
// FIXME: remove if split file
#include "libANGLE/renderer/vulkan/ProgramVk.h"
namespace rx
{
......@@ -146,6 +150,30 @@ void UnpackAttachmentDesc(VkAttachmentDescription *desc,
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);
}
} // anonymous namespace
// Mirrors std_validation_str in loader.h
......@@ -1249,6 +1277,7 @@ void GarbageObject::destroy(VkDevice device)
// RenderPassDesc implementation.
RenderPassDesc::RenderPassDesc()
{
UNUSED_VARIABLE(mPadding);
memset(this, 0, sizeof(RenderPassDesc));
}
......@@ -1444,6 +1473,395 @@ Error InitializeRenderPassFromDesc(VkDevice device,
return vk::NoError();
}
// 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;
}
} // namespace vk
namespace gl_vk
......
......@@ -40,6 +40,8 @@ struct Box;
struct Extents;
struct RasterizerState;
struct Rectangle;
struct VertexAttribute;
class VertexBinding;
ANGLE_GL_OBJECTS_X(ANGLE_PRE_DECLARE_OBJECT);
}
......@@ -52,6 +54,7 @@ class DisplayVk;
class RenderTargetVk;
class RendererVk;
class ResourceVk;
class RenderPassCache;
enum class DrawType
{
......@@ -649,10 +652,25 @@ struct BufferAndMemory final : private angle::NonCopyable
vk::DeviceMemory memory;
};
using CommandBufferAndSerial = ObjectAndSerial<CommandBuffer>;
using FenceAndSerial = ObjectAndSerial<Fence>;
using RenderPassAndSerial = ObjectAndSerial<RenderPass>;
// Packed Vk resource descriptions.
// Most Vk types use many more bits than required to represent the underlying data.
// Since ANGLE wants cache things like RenderPasses and Pipeline State Objects using
// hashing (and also needs to check equality) we can optimize these operations by
// using fewer bits. Hence the packed types.
//
// One implementation note: these types could potentially be improved by using even
// fewer bits. For example, boolean values could be represented by a single bit instead
// of a uint8_t. However at the current time there are concerns about the portability
// of bitfield operators, and complexity issues with using bit mask operations. This is
// something likely we will want to investigate as the Vulkan implementation progresses.
//
// Second implementation note: the struct packing is also a bit fragile, and some of the
// packing requirements depend on using alignas and field ordering to get the result of
// packing nicely into the desired space. This is something we could also potentially fix
// with a redesign to use bitfields or bit mask operations.
struct alignas(4) PackedAttachmentDesc
{
uint8_t flags;
......@@ -660,17 +678,7 @@ struct alignas(4) PackedAttachmentDesc
uint16_t format;
};
struct alignas(8) PackedAttachmentOpsDesc final
{
uint8_t loadOp;
uint8_t storeOp;
uint8_t stencilLoadOp;
uint8_t stencilStoreOp;
// 16-bits to force pad the structure to exactly 8 bytes.
uint16_t initialLayout;
uint16_t finalLayout;
};
static_assert(sizeof(PackedAttachmentDesc) == 4, "Size check failed");
class RenderPassDesc final
{
......@@ -697,10 +705,27 @@ class RenderPassDesc final
uint32_t mColorAttachmentCount;
uint32_t mDepthStencilAttachmentCount;
gl::AttachmentArray<PackedAttachmentDesc> mAttachmentDescs;
uint32_t mPadding[4];
};
bool operator==(const RenderPassDesc &lhs, const RenderPassDesc &rhs);
static_assert(sizeof(RenderPassDesc) == 64, "Size check failed");
struct alignas(8) PackedAttachmentOpsDesc final
{
uint8_t loadOp;
uint8_t storeOp;
uint8_t stencilLoadOp;
uint8_t stencilStoreOp;
// 16-bits to force pad the structure to exactly 8 bytes.
uint16_t initialLayout;
uint16_t finalLayout;
};
static_assert(sizeof(PackedAttachmentOpsDesc) == 8, "Size check failed");
class AttachmentOpsArray final
{
public:
......@@ -723,9 +748,6 @@ class AttachmentOpsArray final
bool operator==(const AttachmentOpsArray &lhs, const AttachmentOpsArray &rhs);
static_assert(sizeof(PackedAttachmentDesc) == 4, "Size check failed");
static_assert(sizeof(PackedAttachmentOpsDesc) == 8, "Size check failed");
static_assert(sizeof(RenderPassDesc) == 48, "Size check failed");
static_assert(sizeof(AttachmentOpsArray) == 80, "Size check failed");
Error InitializeRenderPassFromDesc(VkDevice device,
......@@ -733,6 +755,203 @@ Error InitializeRenderPassFromDesc(VkDevice device,
const AttachmentOpsArray &ops,
RenderPass *renderPass);
struct alignas(8) PackedShaderStageInfo final
{
uint32_t stage;
uint32_t moduleSerial;
// TODO(jmadill): Do we want specialization constants?
};
static_assert(sizeof(PackedShaderStageInfo) == 8, "Size check failed");
struct alignas(4) PackedVertexInputBindingDesc final
{
// Although techncially stride can be any value in ES 2.0, in practice supporting stride
// greater than MAX_USHORT should not be that helpful. Note that stride limits are
// introduced in ES 3.1.
uint16_t stride;
uint16_t inputRate;
};
static_assert(sizeof(PackedVertexInputBindingDesc) == 4, "Size check failed");
struct alignas(8) PackedVertexInputAttributeDesc final
{
uint16_t location;
uint16_t format;
uint32_t offset;
};
static_assert(sizeof(PackedVertexInputAttributeDesc) == 8, "Size check failed");
struct alignas(8) PackedInputAssemblyInfo
{
uint32_t topology;
uint32_t primitiveRestartEnable;
};
static_assert(sizeof(PackedInputAssemblyInfo) == 8, "Size check failed");
struct alignas(32) PackedRasterizationStateInfo
{
// Padded to ensure there's no gaps in this structure or those that use it.
uint32_t depthClampEnable;
uint32_t rasterizationDiscardEnable;
uint16_t polygonMode;
uint16_t cullMode;
uint16_t frontFace;
uint16_t depthBiasEnable;
float depthBiasConstantFactor;
// Note: depth bias clamp is only exposed in a 3.1 extension, but left here for completeness.
float depthBiasClamp;
float depthBiasSlopeFactor;
float lineWidth;
};
static_assert(sizeof(PackedRasterizationStateInfo) == 32, "Size check failed");
struct alignas(16) PackedMultisampleStateInfo final
{
uint8_t rasterizationSamples;
uint8_t sampleShadingEnable;
uint8_t alphaToCoverageEnable;
uint8_t alphaToOneEnable;
float minSampleShading;
uint32_t sampleMask[gl::MAX_SAMPLE_MASK_WORDS];
};
static_assert(sizeof(PackedMultisampleStateInfo) == 16, "Size check failed");
struct alignas(16) PackedStencilOpState final
{
uint8_t failOp;
uint8_t passOp;
uint8_t depthFailOp;
uint8_t compareOp;
uint32_t compareMask;
uint32_t writeMask;
uint32_t reference;
};
static_assert(sizeof(PackedStencilOpState) == 16, "Size check failed");
struct PackedDepthStencilStateInfo final
{
uint8_t depthTestEnable;
uint8_t depthWriteEnable;
uint8_t depthCompareOp;
uint8_t depthBoundsTestEnable;
// 32-bits to pad the alignments.
uint32_t stencilTestEnable;
float minDepthBounds;
float maxDepthBounds;
PackedStencilOpState front;
PackedStencilOpState back;
};
static_assert(sizeof(PackedDepthStencilStateInfo) == 48, "Size check failed");
struct alignas(8) PackedColorBlendAttachmentState final
{
uint8_t blendEnable;
uint8_t srcColorBlendFactor;
uint8_t dstColorBlendFactor;
uint8_t colorBlendOp;
uint8_t srcAlphaBlendFactor;
uint8_t dstAlphaBlendFactor;
uint8_t alphaBlendOp;
uint8_t colorWriteMask;
};
static_assert(sizeof(PackedColorBlendAttachmentState) == 8, "Size check failed");
struct PackedColorBlendStateInfo final
{
// Padded to round the strut size.
uint32_t logicOpEnable;
uint32_t logicOp;
uint32_t attachmentCount;
float blendConstants[4];
PackedColorBlendAttachmentState attachments[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS];
};
static_assert(sizeof(PackedColorBlendStateInfo) == 96, "Size check failed");
using ShaderStageInfo = std::array<PackedShaderStageInfo, 2>;
using VertexInputBindings = gl::AttribArray<PackedVertexInputBindingDesc>;
using VertexInputAttributes = gl::AttribArray<PackedVertexInputAttributeDesc>;
class PipelineDesc final
{
public:
// Use aligned allocation and free so we can use the alignas keyword.
void *operator new(std::size_t size);
void operator delete(void *ptr);
PipelineDesc();
~PipelineDesc();
PipelineDesc(const PipelineDesc &other);
PipelineDesc &operator=(const PipelineDesc &other);
size_t hash() const;
bool operator==(const PipelineDesc &other) const;
void initDefaults();
Error initializePipeline(RendererVk *renderer, ProgramVk *programVk, Pipeline *pipelineOut);
void updateViewport(const gl::Rectangle &viewport, float nearPlane, float farPlane);
// Shader stage info
void updateShaders(ProgramVk *programVk);
// Vertex input state
void resetVertexInputState();
void updateVertexInputInfo(uint32_t attribIndex,
const gl::VertexBinding &binding,
const gl::VertexAttribute &attrib);
// Input assembly info
void updateTopology(GLenum drawMode);
// Raster states
void updateCullMode(const gl::RasterizerState &rasterState);
void updateFrontFace(const gl::RasterizerState &rasterState);
void updateLineWidth(float lineWidth);
// RenderPass description.
void updateRenderPassDesc(const RenderPassDesc &renderPassDesc);
private:
// TODO(jmadill): Handle Geometry/Compute shaders when necessary.
ShaderStageInfo mShaderStageInfo;
VertexInputBindings mVertexInputBindings;
VertexInputAttributes mVertexInputAttribs;
PackedInputAssemblyInfo mInputAssemblyInfo;
// TODO(jmadill): Consider using dynamic state for viewport/scissor.
VkViewport mViewport;
VkRect2D mScissor;
PackedRasterizationStateInfo mRasterizationStateInfo;
PackedMultisampleStateInfo mMultisampleStateInfo;
PackedDepthStencilStateInfo mDepthStencilStateInfo;
PackedColorBlendStateInfo mColorBlendStateInfo;
// TODO(jmadill): Dynamic state.
// TODO(jmadill): Pipeline layout
RenderPassDesc mRenderPassDesc;
};
// Verify the packed pipeline description has no gaps in the packing.
// This is not guaranteed by the spec, but is validated by a compile-time check.
// No gaps or padding at the end ensures that hashing and memcmp checks will not run
// into uninitialized memory regions.
constexpr size_t PipelineDescSumOfSizes =
sizeof(ShaderStageInfo) + sizeof(VertexInputBindings) + sizeof(VertexInputAttributes) +
sizeof(PackedInputAssemblyInfo) + sizeof(VkViewport) + sizeof(VkRect2D) +
sizeof(PackedRasterizationStateInfo) + sizeof(PackedMultisampleStateInfo) +
sizeof(PackedDepthStencilStateInfo) + sizeof(PackedColorBlendStateInfo) +
sizeof(RenderPassDesc);
static_assert(sizeof(PipelineDesc) == PipelineDescSumOfSizes, "Size mismatch");
} // namespace vk
namespace gl_vk
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment