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 ...@@ -71,6 +71,10 @@ class Serial final
{ {
return mValue != kInvalid && mValue == other.mValue; 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 constexpr bool operator!=(const Serial &other) const
{ {
return mValue == kInvalid || mValue != other.mValue; return mValue == kInvalid || mValue != other.mValue;
...@@ -80,6 +84,11 @@ class Serial final ...@@ -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<=(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: private:
friend class SerialFactory; friend class SerialFactory;
constexpr explicit Serial(uint64_t value) : mValue(value) {} constexpr explicit Serial(uint64_t value) : mValue(value) {}
......
...@@ -69,137 +69,6 @@ ContextVk::ContextVk(const gl::ContextState &state, RendererVk *renderer) ...@@ -69,137 +69,6 @@ ContextVk::ContextVk(const gl::ContextState &state, RendererVk *renderer)
mVertexArrayDirty(false), mVertexArrayDirty(false),
mTexturesDirty(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() ContextVk::~ContextVk()
...@@ -238,6 +107,9 @@ gl::Error ContextVk::initialize() ...@@ -238,6 +107,9 @@ gl::Error ContextVk::initialize()
ANGLE_TRY(mDescriptorPool.init(device, descriptorPoolInfo)); ANGLE_TRY(mDescriptorPool.init(device, descriptorPoolInfo));
mPipelineDesc.reset(new vk::PipelineDesc());
mPipelineDesc->initDefaults();
return gl::NoError(); return gl::NoError();
} }
...@@ -257,42 +129,22 @@ gl::Error ContextVk::initPipeline(const gl::Context *context) ...@@ -257,42 +129,22 @@ gl::Error ContextVk::initPipeline(const gl::Context *context)
{ {
ASSERT(!mCurrentPipeline.valid()); ASSERT(!mCurrentPipeline.valid());
VkDevice device = mRenderer->getDevice(); const gl::State &state = mState.getState();
const auto &state = mState.getState(); VertexArrayVk *vertexArrayVk = vk::GetImpl(state.getVertexArray());
const gl::VertexArray *vao = state.getVertexArray(); FramebufferVk *framebufferVk = vk::GetImpl(state.getDrawFramebuffer());
const gl::Framebuffer *drawFBO = state.getDrawFramebuffer(); ProgramVk *programVk = vk::GetImpl(state.getProgram());
FramebufferVk *vkFBO = vk::GetImpl(drawFBO);
VertexArrayVk *vkVAO = vk::GetImpl(vao); // Ensure the topology of the pipeline description is updated.
mPipelineDesc->updateTopology(mCurrentDrawMode);
// Ensure the attribs and bindings are updated. // Ensure the attribs and bindings are updated.
vkVAO->updateVertexDescriptions(context); vertexArrayVk->updateVertexDescriptions(context, mPipelineDesc.get());
const auto &vertexBindings = vkVAO->getVertexBindingDescs(); // Ensure that the RenderPass description is updated.
const auto &vertexAttribs = vkVAO->getVertexAttribDescs(); mPipelineDesc->updateRenderPassDesc(framebufferVk->getRenderPassDesc(context));
// TODO(jmadill): Validate with ASSERT against physical device limits/caps? // TODO(jmadill): Validate with ASSERT against physical device limits/caps?
mCurrentVertexInputState.vertexBindingDescriptionCount = ANGLE_TRY(mPipelineDesc->initializePipeline(mRenderer, programVk, &mCurrentPipeline));
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));
return gl::NoError(); return gl::NoError();
} }
...@@ -569,22 +421,9 @@ void ContextVk::syncState(const gl::Context *context, const gl::State::DirtyBits ...@@ -569,22 +421,9 @@ void ContextVk::syncState(const gl::Context *context, const gl::State::DirtyBits
WARN() << "DIRTY_BIT_SCISSOR unimplemented"; WARN() << "DIRTY_BIT_SCISSOR unimplemented";
break; break;
case gl::State::DIRTY_BIT_VIEWPORT: case gl::State::DIRTY_BIT_VIEWPORT:
{ mPipelineDesc->updateViewport(glState.getViewport(), glState.getNearPlane(),
const gl::Rectangle &viewportGL = glState.getViewport(); glState.getFarPlane());
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;
break; break;
}
case gl::State::DIRTY_BIT_DEPTH_RANGE: case gl::State::DIRTY_BIT_DEPTH_RANGE:
WARN() << "DIRTY_BIT_DEPTH_RANGE unimplemented"; WARN() << "DIRTY_BIT_DEPTH_RANGE unimplemented";
break; break;
...@@ -650,11 +489,10 @@ void ContextVk::syncState(const gl::Context *context, const gl::State::DirtyBits ...@@ -650,11 +489,10 @@ void ContextVk::syncState(const gl::Context *context, const gl::State::DirtyBits
break; break;
case gl::State::DIRTY_BIT_CULL_FACE_ENABLED: case gl::State::DIRTY_BIT_CULL_FACE_ENABLED:
case gl::State::DIRTY_BIT_CULL_FACE: case gl::State::DIRTY_BIT_CULL_FACE:
mCurrentRasterState.cullMode = gl_vk::GetCullMode(glState.getRasterizerState()); mPipelineDesc->updateCullMode(glState.getRasterizerState());
break; break;
case gl::State::DIRTY_BIT_FRONT_FACE: case gl::State::DIRTY_BIT_FRONT_FACE:
mCurrentRasterState.frontFace = mPipelineDesc->updateFrontFace(glState.getRasterizerState());
gl_vk::GetFrontFace(glState.getRasterizerState().frontFace);
break; break;
case gl::State::DIRTY_BIT_POLYGON_OFFSET_FILL_ENABLED: case gl::State::DIRTY_BIT_POLYGON_OFFSET_FILL_ENABLED:
WARN() << "DIRTY_BIT_POLYGON_OFFSET_FILL_ENABLED unimplemented"; WARN() << "DIRTY_BIT_POLYGON_OFFSET_FILL_ENABLED unimplemented";
...@@ -666,7 +504,7 @@ void ContextVk::syncState(const gl::Context *context, const gl::State::DirtyBits ...@@ -666,7 +504,7 @@ void ContextVk::syncState(const gl::Context *context, const gl::State::DirtyBits
WARN() << "DIRTY_BIT_RASTERIZER_DISCARD_ENABLED unimplemented"; WARN() << "DIRTY_BIT_RASTERIZER_DISCARD_ENABLED unimplemented";
break; break;
case gl::State::DIRTY_BIT_LINE_WIDTH: case gl::State::DIRTY_BIT_LINE_WIDTH:
mCurrentRasterState.lineWidth = glState.getLineWidth(); mPipelineDesc->updateLineWidth(glState.getLineWidth());
break; break;
case gl::State::DIRTY_BIT_PRIMITIVE_RESTART_ENABLED: case gl::State::DIRTY_BIT_PRIMITIVE_RESTART_ENABLED:
WARN() << "DIRTY_BIT_PRIMITIVE_RESTART_ENABLED unimplemented"; WARN() << "DIRTY_BIT_PRIMITIVE_RESTART_ENABLED unimplemented";
...@@ -711,8 +549,12 @@ void ContextVk::syncState(const gl::Context *context, const gl::State::DirtyBits ...@@ -711,8 +549,12 @@ void ContextVk::syncState(const gl::Context *context, const gl::State::DirtyBits
WARN() << "DIRTY_BIT_RENDERBUFFER_BINDING unimplemented"; WARN() << "DIRTY_BIT_RENDERBUFFER_BINDING unimplemented";
break; break;
case gl::State::DIRTY_BIT_VERTEX_ARRAY_BINDING: case gl::State::DIRTY_BIT_VERTEX_ARRAY_BINDING:
{
VertexArrayVk *vertexArrayVk = vk::GetImpl(glState.getVertexArray());
vertexArrayVk->invalidateVertexDescriptions();
mVertexArrayDirty = true; mVertexArrayDirty = true;
break; break;
}
case gl::State::DIRTY_BIT_DRAW_INDIRECT_BUFFER_BINDING: case gl::State::DIRTY_BIT_DRAW_INDIRECT_BUFFER_BINDING:
WARN() << "DIRTY_BIT_DRAW_INDIRECT_BUFFER_BINDING unimplemented"; WARN() << "DIRTY_BIT_DRAW_INDIRECT_BUFFER_BINDING unimplemented";
break; break;
...@@ -724,14 +566,12 @@ void ContextVk::syncState(const gl::Context *context, const gl::State::DirtyBits ...@@ -724,14 +566,12 @@ void ContextVk::syncState(const gl::Context *context, const gl::State::DirtyBits
break; break;
case gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE: case gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE:
{ {
// { vertex, fragment } ProgramVk *programVk = vk::GetImpl(glState.getProgram());
ProgramVk *programVk = vk::GetImpl(glState.getProgram()); mPipelineDesc->updateShaders(programVk);
mCurrentShaderStages[0].module = programVk->getLinkedVertexModule().getHandle();
mCurrentShaderStages[1].module = programVk->getLinkedFragmentModule().getHandle();
// Also invalidate the vertex descriptions cache in the Vertex Array. // Also invalidate the vertex descriptions cache in the Vertex Array.
VertexArrayVk *vaoVk = vk::GetImpl(glState.getVertexArray()); VertexArrayVk *vertexArrayVk = vk::GetImpl(glState.getVertexArray());
vaoVk->invalidateVertexDescriptions(); vertexArrayVk->invalidateVertexDescriptions();
dirtyTextures = true; dirtyTextures = true;
break; break;
......
...@@ -170,21 +170,9 @@ class ContextVk : public ContextImpl, public ResourceVk ...@@ -170,21 +170,9 @@ class ContextVk : public ContextImpl, public ResourceVk
vk::Pipeline mCurrentPipeline; vk::Pipeline mCurrentPipeline;
GLenum mCurrentDrawMode; GLenum mCurrentDrawMode;
// Keep CreateInfo structures cached so that we can quickly update them when creating // Keep a cached pipeline description structure that can be used to query the pipeline cache.
// updated pipelines. When we move to a pipeline cache, we will want to use a more compact // Kept in a pointer so allocations can be aligned, and structs can be portably packed.
// structure that we can use to query the pipeline cache in the Renderer. std::unique_ptr<vk::PipelineDesc> mPipelineDesc;
// 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;
// The descriptor pool is externally sychronized, so cannot be accessed from different threads // 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. // simulataneously. Hence, we keep it in the ContextVk instead of the RendererVk.
......
...@@ -167,6 +167,8 @@ void ProgramVk::reset(VkDevice device) ...@@ -167,6 +167,8 @@ void ProgramVk::reset(VkDevice device)
mLinkedFragmentModule.destroy(device); mLinkedFragmentModule.destroy(device);
mLinkedVertexModule.destroy(device); mLinkedVertexModule.destroy(device);
mVertexModuleSerial = Serial();
mFragmentModuleSerial = Serial();
// Descriptor Sets are pool allocated, so do not need to be explicitly freed. // Descriptor Sets are pool allocated, so do not need to be explicitly freed.
mDescriptorSets.clear(); mDescriptorSets.clear();
...@@ -228,6 +230,7 @@ gl::LinkResult ProgramVk::link(const gl::Context *glContext, ...@@ -228,6 +230,7 @@ gl::LinkResult ProgramVk::link(const gl::Context *glContext,
vertexShaderInfo.pCode = vertexCode.data(); vertexShaderInfo.pCode = vertexCode.data();
ANGLE_TRY(mLinkedVertexModule.init(device, vertexShaderInfo)); ANGLE_TRY(mLinkedVertexModule.init(device, vertexShaderInfo));
mVertexModuleSerial = renderer->issueProgramSerial();
} }
{ {
...@@ -239,6 +242,7 @@ gl::LinkResult ProgramVk::link(const gl::Context *glContext, ...@@ -239,6 +242,7 @@ gl::LinkResult ProgramVk::link(const gl::Context *glContext,
fragmentShaderInfo.pCode = fragmentCode.data(); fragmentShaderInfo.pCode = fragmentCode.data();
ANGLE_TRY(mLinkedFragmentModule.init(device, fragmentShaderInfo)); ANGLE_TRY(mLinkedFragmentModule.init(device, fragmentShaderInfo));
mFragmentModuleSerial = renderer->issueProgramSerial();
} }
ANGLE_TRY(initDescriptorSets(contextVk)); ANGLE_TRY(initDescriptorSets(contextVk));
...@@ -546,12 +550,22 @@ const vk::ShaderModule &ProgramVk::getLinkedVertexModule() const ...@@ -546,12 +550,22 @@ const vk::ShaderModule &ProgramVk::getLinkedVertexModule() const
return mLinkedVertexModule; return mLinkedVertexModule;
} }
Serial ProgramVk::getVertexModuleSerial() const
{
return mVertexModuleSerial;
}
const vk::ShaderModule &ProgramVk::getLinkedFragmentModule() const const vk::ShaderModule &ProgramVk::getLinkedFragmentModule() const
{ {
ASSERT(mLinkedFragmentModule.getHandle() != VK_NULL_HANDLE); ASSERT(mLinkedFragmentModule.getHandle() != VK_NULL_HANDLE);
return mLinkedFragmentModule; return mLinkedFragmentModule;
} }
Serial ProgramVk::getFragmentModuleSerial() const
{
return mFragmentModuleSerial;
}
vk::Error ProgramVk::initDescriptorSets(ContextVk *contextVk) vk::Error ProgramVk::initDescriptorSets(ContextVk *contextVk)
{ {
ASSERT(mDescriptorSets.empty()); ASSERT(mDescriptorSets.empty());
......
...@@ -100,7 +100,9 @@ class ProgramVk : public ProgramImpl ...@@ -100,7 +100,9 @@ class ProgramVk : public ProgramImpl
const GLfloat *coeffs) override; const GLfloat *coeffs) override;
const vk::ShaderModule &getLinkedVertexModule() const; const vk::ShaderModule &getLinkedVertexModule() const;
Serial getVertexModuleSerial() const;
const vk::ShaderModule &getLinkedFragmentModule() const; const vk::ShaderModule &getLinkedFragmentModule() const;
Serial getFragmentModuleSerial() const;
vk::Error updateUniforms(ContextVk *contextVk); vk::Error updateUniforms(ContextVk *contextVk);
...@@ -127,7 +129,9 @@ class ProgramVk : public ProgramImpl ...@@ -127,7 +129,9 @@ class ProgramVk : public ProgramImpl
void setUniformImpl(GLint location, GLsizei count, const T *v, GLenum entryPointType); void setUniformImpl(GLint location, GLsizei count, const T *v, GLenum entryPointType);
vk::ShaderModule mLinkedVertexModule; vk::ShaderModule mLinkedVertexModule;
Serial mVertexModuleSerial;
vk::ShaderModule mLinkedFragmentModule; vk::ShaderModule mLinkedFragmentModule;
Serial mFragmentModuleSerial;
// State for the default uniform blocks. // State for the default uniform blocks.
struct DefaultUniformBlock final : private angle::NonCopyable struct DefaultUniformBlock final : private angle::NonCopyable
......
...@@ -1070,4 +1070,10 @@ vk::Error RendererVk::initGraphicsPipelineLayout() ...@@ -1070,4 +1070,10 @@ vk::Error RendererVk::initGraphicsPipelineLayout()
return vk::NoError(); return vk::NoError();
} }
Serial RendererVk::issueProgramSerial()
{
return mProgramSerialFactory.generate();
}
} // namespace rx } // namespace rx
...@@ -147,6 +147,9 @@ class RendererVk : angle::NonCopyable ...@@ -147,6 +147,9 @@ class RendererVk : angle::NonCopyable
const vk::PipelineLayout &getGraphicsPipelineLayout() const; const vk::PipelineLayout &getGraphicsPipelineLayout() const;
const std::vector<vk::DescriptorSetLayout> &getGraphicsDescriptorSetLayouts() const; const std::vector<vk::DescriptorSetLayout> &getGraphicsDescriptorSetLayouts() const;
// Issues a new serial for linked shader modules. Used in the pipeline cache.
Serial issueProgramSerial();
private: private:
vk::Error initializeDevice(uint32_t queueFamilyIndex); vk::Error initializeDevice(uint32_t queueFamilyIndex);
void ensureCapsInitialized() const; void ensureCapsInitialized() const;
...@@ -179,6 +182,7 @@ class RendererVk : angle::NonCopyable ...@@ -179,6 +182,7 @@ class RendererVk : angle::NonCopyable
vk::CommandPool mCommandPool; vk::CommandPool mCommandPool;
GlslangWrapper *mGlslangWrapper; GlslangWrapper *mGlslangWrapper;
SerialFactory mQueueSerialFactory; SerialFactory mQueueSerialFactory;
SerialFactory mProgramSerialFactory;
Serial mLastCompletedQueueSerial; Serial mLastCompletedQueueSerial;
Serial mCurrentQueueSerial; Serial mCurrentQueueSerial;
......
...@@ -29,8 +29,6 @@ VertexArrayVk::VertexArrayVk(const gl::VertexArrayState &state) ...@@ -29,8 +29,6 @@ VertexArrayVk::VertexArrayVk(const gl::VertexArrayState &state)
{ {
mCurrentArrayBufferHandles.fill(VK_NULL_HANDLE); mCurrentArrayBufferHandles.fill(VK_NULL_HANDLE);
mCurrentArrayBufferResources.fill(nullptr); mCurrentArrayBufferResources.fill(nullptr);
mCurrentVertexBindingDescs.reserve(state.getMaxAttribs());
mCurrentVertexAttribDescs.reserve(state.getMaxAttribs());
} }
VertexArrayVk::~VertexArrayVk() VertexArrayVk::~VertexArrayVk()
...@@ -131,11 +129,10 @@ void VertexArrayVk::updateDrawDependencies(vk::CommandBufferNode *readNode, ...@@ -131,11 +129,10 @@ void VertexArrayVk::updateDrawDependencies(vk::CommandBufferNode *readNode,
void VertexArrayVk::invalidateVertexDescriptions() void VertexArrayVk::invalidateVertexDescriptions()
{ {
mCurrentVertexDescsValid = false; 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) if (mCurrentVertexDescsValid)
{ {
...@@ -147,29 +144,16 @@ void VertexArrayVk::updateVertexDescriptions(const gl::Context *context) ...@@ -147,29 +144,16 @@ void VertexArrayVk::updateVertexDescriptions(const gl::Context *context)
const gl::Program *programGL = context->getGLState().getProgram(); const gl::Program *programGL = context->getGLState().getProgram();
pipelineDesc->resetVertexInputState();
for (auto attribIndex : programGL->getActiveAttribLocationsMask()) for (auto attribIndex : programGL->getActiveAttribLocationsMask())
{ {
const auto &attrib = attribs[attribIndex]; const auto &attrib = attribs[attribIndex];
const auto &binding = bindings[attrib.bindingIndex]; const auto &binding = bindings[attrib.bindingIndex];
if (attrib.enabled) if (attrib.enabled)
{ {
VkVertexInputBindingDescription bindingDesc; pipelineDesc->updateVertexInputInfo(static_cast<uint32_t>(attribIndex), binding,
bindingDesc.binding = static_cast<uint32_t>(mCurrentVertexBindingDescs.size()); attrib);
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);
} }
else else
{ {
...@@ -180,14 +164,4 @@ void VertexArrayVk::updateVertexDescriptions(const gl::Context *context) ...@@ -180,14 +164,4 @@ void VertexArrayVk::updateVertexDescriptions(const gl::Context *context)
mCurrentVertexDescsValid = true; mCurrentVertexDescsValid = true;
} }
const std::vector<VkVertexInputBindingDescription> &VertexArrayVk::getVertexBindingDescs() const
{
return mCurrentVertexBindingDescs;
}
const std::vector<VkVertexInputAttributeDescription> &VertexArrayVk::getVertexAttribDescs() const
{
return mCurrentVertexAttribDescs;
}
} // namespace rx } // namespace rx
...@@ -36,10 +36,7 @@ class VertexArrayVk : public VertexArrayImpl ...@@ -36,10 +36,7 @@ class VertexArrayVk : public VertexArrayImpl
DrawType drawType); DrawType drawType);
void invalidateVertexDescriptions(); void invalidateVertexDescriptions();
void updateVertexDescriptions(const gl::Context *context); void updateVertexDescriptions(const gl::Context *context, vk::PipelineDesc *pipelineDesc);
const std::vector<VkVertexInputBindingDescription> &getVertexBindingDescs() const;
const std::vector<VkVertexInputAttributeDescription> &getVertexAttribDescs() const;
private: private:
gl::AttribArray<VkBuffer> mCurrentArrayBufferHandles; gl::AttribArray<VkBuffer> mCurrentArrayBufferHandles;
...@@ -49,8 +46,6 @@ class VertexArrayVk : public VertexArrayImpl ...@@ -49,8 +46,6 @@ class VertexArrayVk : public VertexArrayImpl
// Keep a cache of binding and attribute descriptions for easy pipeline updates. // Keep a cache of binding and attribute descriptions for easy pipeline updates.
// TODO(jmadill): Update this when we support pipeline caching. // TODO(jmadill): Update this when we support pipeline caching.
bool mCurrentVertexDescsValid; bool mCurrentVertexDescsValid;
std::vector<VkVertexInputBindingDescription> mCurrentVertexBindingDescs;
std::vector<VkVertexInputAttributeDescription> mCurrentVertexAttribDescs;
}; };
} // namespace rx } // namespace rx
......
...@@ -7,8 +7,9 @@ ...@@ -7,8 +7,9 @@
// Helper functions for the Vulkan Renderer. // 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/Context.h"
#include "libANGLE/SizedMRUCache.h" #include "libANGLE/SizedMRUCache.h"
#include "libANGLE/renderer/vulkan/CommandBufferNode.h" #include "libANGLE/renderer/vulkan/CommandBufferNode.h"
...@@ -16,6 +17,9 @@ ...@@ -16,6 +17,9 @@
#include "libANGLE/renderer/vulkan/RenderTargetVk.h" #include "libANGLE/renderer/vulkan/RenderTargetVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h" #include "libANGLE/renderer/vulkan/RendererVk.h"
// FIXME: remove if split file
#include "libANGLE/renderer/vulkan/ProgramVk.h"
namespace rx namespace rx
{ {
...@@ -146,6 +150,30 @@ void UnpackAttachmentDesc(VkAttachmentDescription *desc, ...@@ -146,6 +150,30 @@ void UnpackAttachmentDesc(VkAttachmentDescription *desc,
desc->finalLayout = static_cast<VkImageLayout>(ops.finalLayout); 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 } // anonymous namespace
// Mirrors std_validation_str in loader.h // Mirrors std_validation_str in loader.h
...@@ -1249,6 +1277,7 @@ void GarbageObject::destroy(VkDevice device) ...@@ -1249,6 +1277,7 @@ void GarbageObject::destroy(VkDevice device)
// RenderPassDesc implementation. // RenderPassDesc implementation.
RenderPassDesc::RenderPassDesc() RenderPassDesc::RenderPassDesc()
{ {
UNUSED_VARIABLE(mPadding);
memset(this, 0, sizeof(RenderPassDesc)); memset(this, 0, sizeof(RenderPassDesc));
} }
...@@ -1444,6 +1473,395 @@ Error InitializeRenderPassFromDesc(VkDevice device, ...@@ -1444,6 +1473,395 @@ Error InitializeRenderPassFromDesc(VkDevice device,
return vk::NoError(); 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 vk
namespace gl_vk namespace gl_vk
......
...@@ -40,6 +40,8 @@ struct Box; ...@@ -40,6 +40,8 @@ struct Box;
struct Extents; struct Extents;
struct RasterizerState; struct RasterizerState;
struct Rectangle; struct Rectangle;
struct VertexAttribute;
class VertexBinding;
ANGLE_GL_OBJECTS_X(ANGLE_PRE_DECLARE_OBJECT); ANGLE_GL_OBJECTS_X(ANGLE_PRE_DECLARE_OBJECT);
} }
...@@ -52,6 +54,7 @@ class DisplayVk; ...@@ -52,6 +54,7 @@ class DisplayVk;
class RenderTargetVk; class RenderTargetVk;
class RendererVk; class RendererVk;
class ResourceVk; class ResourceVk;
class RenderPassCache;
enum class DrawType enum class DrawType
{ {
...@@ -649,9 +652,24 @@ struct BufferAndMemory final : private angle::NonCopyable ...@@ -649,9 +652,24 @@ struct BufferAndMemory final : private angle::NonCopyable
vk::DeviceMemory memory; vk::DeviceMemory memory;
}; };
using CommandBufferAndSerial = ObjectAndSerial<CommandBuffer>; using RenderPassAndSerial = ObjectAndSerial<RenderPass>;
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 struct alignas(4) PackedAttachmentDesc
{ {
...@@ -660,17 +678,7 @@ struct alignas(4) PackedAttachmentDesc ...@@ -660,17 +678,7 @@ struct alignas(4) PackedAttachmentDesc
uint16_t format; uint16_t format;
}; };
struct alignas(8) PackedAttachmentOpsDesc final static_assert(sizeof(PackedAttachmentDesc) == 4, "Size check failed");
{
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;
};
class RenderPassDesc final class RenderPassDesc final
{ {
...@@ -697,10 +705,27 @@ class RenderPassDesc final ...@@ -697,10 +705,27 @@ class RenderPassDesc final
uint32_t mColorAttachmentCount; uint32_t mColorAttachmentCount;
uint32_t mDepthStencilAttachmentCount; uint32_t mDepthStencilAttachmentCount;
gl::AttachmentArray<PackedAttachmentDesc> mAttachmentDescs; gl::AttachmentArray<PackedAttachmentDesc> mAttachmentDescs;
uint32_t mPadding[4];
}; };
bool operator==(const RenderPassDesc &lhs, const RenderPassDesc &rhs); 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 class AttachmentOpsArray final
{ {
public: public:
...@@ -723,9 +748,6 @@ class AttachmentOpsArray final ...@@ -723,9 +748,6 @@ class AttachmentOpsArray final
bool operator==(const AttachmentOpsArray &lhs, const AttachmentOpsArray &rhs); 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"); static_assert(sizeof(AttachmentOpsArray) == 80, "Size check failed");
Error InitializeRenderPassFromDesc(VkDevice device, Error InitializeRenderPassFromDesc(VkDevice device,
...@@ -733,6 +755,203 @@ Error InitializeRenderPassFromDesc(VkDevice device, ...@@ -733,6 +755,203 @@ Error InitializeRenderPassFromDesc(VkDevice device,
const AttachmentOpsArray &ops, const AttachmentOpsArray &ops,
RenderPass *renderPass); 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 vk
namespace gl_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