Dynamic state implementation
Implemented all dynamic state commands and applied
the proper state within the draw command.
Bug b/118619338
Change-Id: Ifeca42be1698f642e137e807aa59958447921fcc
Tests: dEQP-VK.dynamic_state.*
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/28890
Tested-by: Alexis Hétu <sugoi@google.com>
Presubmit-Ready: Alexis Hétu <sugoi@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Chris Forbes <chrisforbes@google.com>
diff --git a/src/Device/Context.cpp b/src/Device/Context.cpp
index f3721ef..a7198b7 100644
--- a/src/Device/Context.cpp
+++ b/src/Device/Context.cpp
@@ -133,6 +133,7 @@
rasterizerDiscard = false;
depthCompareMode = VK_COMPARE_OP_LESS;
+ depthBoundsTestEnable = false;
depthBufferEnable = false;
depthWriteEnable = false;
diff --git a/src/Device/Context.hpp b/src/Device/Context.hpp
index ba9837a..e692762 100644
--- a/src/Device/Context.hpp
+++ b/src/Device/Context.hpp
@@ -179,6 +179,7 @@
// Pixel processor states
bool rasterizerDiscard;
+ bool depthBoundsTestEnable;
bool depthBufferEnable;
VkCompareOp depthCompareMode;
bool depthWriteEnable;
diff --git a/src/Vulkan/VkCommandBuffer.cpp b/src/Vulkan/VkCommandBuffer.cpp
index bd3b6f5..0af06da 100644
--- a/src/Vulkan/VkCommandBuffer.cpp
+++ b/src/Vulkan/VkCommandBuffer.cpp
@@ -250,6 +250,157 @@
const VkIndexType indexType;
};
+struct SetViewport : public CommandBuffer::Command
+{
+ SetViewport(const VkViewport& viewport, uint32_t viewportID) :
+ viewport(viewport), viewportID(viewportID)
+ {
+ }
+
+ void play(CommandBuffer::ExecutionState& executionState) override
+ {
+ executionState.dynamicState.viewport = viewport;
+ }
+
+ const VkViewport viewport;
+ uint32_t viewportID;
+};
+
+struct SetScissor : public CommandBuffer::Command
+{
+ SetScissor(const VkRect2D& scissor, uint32_t scissorID) :
+ scissor(scissor), scissorID(scissorID)
+ {
+ }
+
+ void play(CommandBuffer::ExecutionState& executionState) override
+ {
+ executionState.dynamicState.scissor = scissor;
+ }
+
+ const VkRect2D scissor;
+ uint32_t scissorID;
+};
+
+struct SetDepthBias : public CommandBuffer::Command
+{
+ SetDepthBias(float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor) :
+ depthBiasConstantFactor(depthBiasConstantFactor), depthBiasClamp(depthBiasClamp), depthBiasSlopeFactor(depthBiasSlopeFactor)
+ {
+ }
+
+ void play(CommandBuffer::ExecutionState& executionState) override
+ {
+ executionState.dynamicState.depthBiasConstantFactor = depthBiasConstantFactor;
+ executionState.dynamicState.depthBiasClamp = depthBiasClamp;
+ executionState.dynamicState.depthBiasSlopeFactor = depthBiasSlopeFactor;
+ }
+
+ float depthBiasConstantFactor;
+ float depthBiasClamp;
+ float depthBiasSlopeFactor;
+};
+
+struct SetBlendConstants : public CommandBuffer::Command
+{
+ SetBlendConstants(const float blendConstants[4])
+ {
+ memcpy(this->blendConstants, blendConstants, sizeof(this->blendConstants));
+ }
+
+ void play(CommandBuffer::ExecutionState& executionState) override
+ {
+ memcpy(&(executionState.dynamicState.blendConstants[0]), blendConstants, sizeof(blendConstants));
+ }
+
+ float blendConstants[4];
+};
+
+struct SetDepthBounds : public CommandBuffer::Command
+{
+ SetDepthBounds(float minDepthBounds, float maxDepthBounds) :
+ minDepthBounds(minDepthBounds), maxDepthBounds(maxDepthBounds)
+ {
+ }
+
+ void play(CommandBuffer::ExecutionState& executionState) override
+ {
+ executionState.dynamicState.minDepthBounds = minDepthBounds;
+ executionState.dynamicState.maxDepthBounds = maxDepthBounds;
+ }
+
+ float minDepthBounds;
+ float maxDepthBounds;
+};
+struct SetStencilCompareMask : public CommandBuffer::Command
+{
+ SetStencilCompareMask(VkStencilFaceFlags faceMask, uint32_t compareMask) :
+ faceMask(faceMask), compareMask(compareMask)
+ {
+ }
+
+ void play(CommandBuffer::ExecutionState& executionState) override
+ {
+ if(faceMask & VK_STENCIL_FACE_FRONT_BIT)
+ {
+ executionState.dynamicState.compareMask[0] = compareMask;
+ }
+ if(faceMask & VK_STENCIL_FACE_BACK_BIT)
+ {
+ executionState.dynamicState.compareMask[1] = compareMask;
+ }
+ }
+
+ VkStencilFaceFlags faceMask;
+ uint32_t compareMask;
+};
+
+struct SetStencilWriteMask : public CommandBuffer::Command
+{
+ SetStencilWriteMask(VkStencilFaceFlags faceMask, uint32_t writeMask) :
+ faceMask(faceMask), writeMask(writeMask)
+ {
+ }
+
+ void play(CommandBuffer::ExecutionState& executionState) override
+ {
+ if(faceMask & VK_STENCIL_FACE_FRONT_BIT)
+ {
+ executionState.dynamicState.writeMask[0] = writeMask;
+ }
+ if(faceMask & VK_STENCIL_FACE_BACK_BIT)
+ {
+ executionState.dynamicState.writeMask[1] = writeMask;
+ }
+ }
+
+ VkStencilFaceFlags faceMask;
+ uint32_t writeMask;
+};
+
+struct SetStencilReference : public CommandBuffer::Command
+{
+ SetStencilReference(VkStencilFaceFlags faceMask, uint32_t reference) :
+ faceMask(faceMask), reference(reference)
+ {
+ }
+
+ void play(CommandBuffer::ExecutionState& executionState) override
+ {
+ if(faceMask & VK_STENCIL_FACE_FRONT_BIT)
+ {
+ executionState.dynamicState.reference[0] = reference;
+ }
+ if(faceMask & VK_STENCIL_FACE_BACK_BIT)
+ {
+ executionState.dynamicState.reference[1] = reference;
+ }
+ }
+
+ VkStencilFaceFlags faceMask;
+ uint32_t reference;
+};
+
void CommandBuffer::ExecutionState::bindVertexInputs(sw::Context& context, int firstVertex, int firstInstance)
{
for(uint32_t i = 0; i < MAX_VERTEX_INPUT_BINDINGS; i++)
@@ -319,16 +470,52 @@
context.descriptorDynamicOffsets = pipelineState.descriptorDynamicOffsets;
context.pushConstants = executionState.pushConstants;
- if (indexed)
+ if(indexed)
{
context.indexBuffer = Cast(executionState.indexBufferBinding.buffer)->getOffsetPointer(
executionState.indexBufferBinding.offset + first * bytesPerIndex(executionState));
}
+ // Apply either pipeline state or dynamic state
+ executionState.renderer->setScissor(pipeline->hasDynamicState(VK_DYNAMIC_STATE_SCISSOR) ?
+ executionState.dynamicState.scissor : pipeline->getScissor());
+ executionState.renderer->setViewport(pipeline->hasDynamicState(VK_DYNAMIC_STATE_VIEWPORT) ?
+ executionState.dynamicState.viewport : pipeline->getViewport());
+ executionState.renderer->setBlendConstant(pipeline->hasDynamicState(VK_DYNAMIC_STATE_BLEND_CONSTANTS) ?
+ executionState.dynamicState.blendConstants : pipeline->getBlendConstants());
+ if(pipeline->hasDynamicState(VK_DYNAMIC_STATE_DEPTH_BIAS))
+ {
+ // If the depth bias clamping feature is not enabled, depthBiasClamp must be 0.0
+ ASSERT(executionState.dynamicState.depthBiasClamp == 0.0f);
+
+ context.depthBias = executionState.dynamicState.depthBiasConstantFactor;
+ context.slopeDepthBias = executionState.dynamicState.depthBiasSlopeFactor;
+ }
+ if(pipeline->hasDynamicState(VK_DYNAMIC_STATE_DEPTH_BOUNDS) && context.depthBoundsTestEnable)
+ {
+ // Unless the VK_EXT_depth_range_unrestricted extension is enabled minDepthBounds and maxDepthBounds must be between 0.0 and 1.0, inclusive
+ ASSERT(executionState.dynamicState.minDepthBounds >= 0.0f && executionState.dynamicState.minDepthBounds <= 1.0f);
+ ASSERT(executionState.dynamicState.maxDepthBounds >= 0.0f && executionState.dynamicState.maxDepthBounds <= 1.0f);
+
+ UNIMPLEMENTED("depthBoundsTestEnable");
+ }
+ if(pipeline->hasDynamicState(VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK) && context.stencilEnable)
+ {
+ context.frontStencil.compareMask = executionState.dynamicState.compareMask[0];
+ context.backStencil.compareMask = executionState.dynamicState.compareMask[1];
+ }
+ if(pipeline->hasDynamicState(VK_DYNAMIC_STATE_STENCIL_WRITE_MASK) && context.stencilEnable)
+ {
+ context.frontStencil.writeMask = executionState.dynamicState.writeMask[0];
+ context.backStencil.writeMask = executionState.dynamicState.writeMask[1];
+ }
+ if(pipeline->hasDynamicState(VK_DYNAMIC_STATE_STENCIL_REFERENCE) && context.stencilEnable)
+ {
+ context.frontStencil.reference = executionState.dynamicState.reference[0];
+ context.backStencil.reference = executionState.dynamicState.reference[1];
+ }
+
executionState.renderer->setContext(context);
- executionState.renderer->setScissor(pipeline->getScissor());
- executionState.renderer->setViewport(pipeline->getViewport());
- executionState.renderer->setBlendConstant(pipeline->getBlendConstants());
executionState.bindAttachments();
@@ -1008,85 +1195,73 @@
void CommandBuffer::setViewport(uint32_t firstViewport, uint32_t viewportCount, const VkViewport* pViewports)
{
- // Note: The bound graphics pipeline must have been created with the VK_DYNAMIC_STATE_VIEWPORT dynamic state enabled
- UNIMPLEMENTED("setViewport");
+ if(firstViewport != 0 || viewportCount > 1)
+ {
+ UNIMPLEMENTED("viewport");
+ }
+
+ for(uint32_t i = 0; i < viewportCount; i++)
+ {
+ addCommand<SetViewport>(pViewports[i], i + firstViewport);
+ }
}
void CommandBuffer::setScissor(uint32_t firstScissor, uint32_t scissorCount, const VkRect2D* pScissors)
{
- // Note: The bound graphics pipeline must have been created with the VK_DYNAMIC_STATE_SCISSOR dynamic state enabled
- UNIMPLEMENTED("setScissor");
+ if(firstScissor != 0 || scissorCount > 1)
+ {
+ UNIMPLEMENTED("scissor");
+ }
+
+ for(uint32_t i = 0; i < scissorCount; i++)
+ {
+ addCommand<SetScissor>(pScissors[i], i + firstScissor);
+ }
}
void CommandBuffer::setLineWidth(float lineWidth)
{
- // Note: The bound graphics pipeline must have been created with the VK_DYNAMIC_STATE_LINE_WIDTH dynamic state enabled
-
// If the wide lines feature is not enabled, lineWidth must be 1.0
ASSERT(lineWidth == 1.0f);
-
- UNIMPLEMENTED("setLineWidth");
}
void CommandBuffer::setDepthBias(float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor)
{
- // Note: The bound graphics pipeline must have been created with the VK_DYNAMIC_STATE_DEPTH_BIAS dynamic state enabled
-
- // If the depth bias clamping feature is not enabled, depthBiasClamp must be 0.0
- ASSERT(depthBiasClamp == 0.0f);
-
- UNIMPLEMENTED("setDepthBias");
+ addCommand<SetDepthBias>(depthBiasConstantFactor, depthBiasClamp, depthBiasSlopeFactor);
}
void CommandBuffer::setBlendConstants(const float blendConstants[4])
{
- // Note: The bound graphics pipeline must have been created with the VK_DYNAMIC_STATE_BLEND_CONSTANTS dynamic state enabled
-
- // blendConstants is an array of four values specifying the R, G, B, and A components
- // of the blend constant color used in blending, depending on the blend factor.
-
- UNIMPLEMENTED("setBlendConstants");
+ addCommand<SetBlendConstants>(blendConstants);
}
void CommandBuffer::setDepthBounds(float minDepthBounds, float maxDepthBounds)
{
- // Note: The bound graphics pipeline must have been created with the VK_DYNAMIC_STATE_DEPTH_BOUNDS dynamic state enabled
-
- // Unless the VK_EXT_depth_range_unrestricted extension is enabled minDepthBounds and maxDepthBounds must be between 0.0 and 1.0, inclusive
- ASSERT(minDepthBounds >= 0.0f && minDepthBounds <= 1.0f);
- ASSERT(maxDepthBounds >= 0.0f && maxDepthBounds <= 1.0f);
-
- UNIMPLEMENTED("setDepthBounds");
+ addCommand<SetDepthBounds>(minDepthBounds, maxDepthBounds);
}
void CommandBuffer::setStencilCompareMask(VkStencilFaceFlags faceMask, uint32_t compareMask)
{
- // Note: The bound graphics pipeline must have been created with the VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK dynamic state enabled
-
// faceMask must not be 0
ASSERT(faceMask != 0);
- UNIMPLEMENTED("setStencilCompareMask");
+ addCommand<SetStencilCompareMask>(faceMask, compareMask);
}
void CommandBuffer::setStencilWriteMask(VkStencilFaceFlags faceMask, uint32_t writeMask)
{
- // Note: The bound graphics pipeline must have been created with the VK_DYNAMIC_STATE_STENCIL_WRITE_MASK dynamic state enabled
-
// faceMask must not be 0
ASSERT(faceMask != 0);
- UNIMPLEMENTED("setStencilWriteMask");
+ addCommand<SetStencilWriteMask>(faceMask, writeMask);
}
void CommandBuffer::setStencilReference(VkStencilFaceFlags faceMask, uint32_t reference)
{
- // Note: The bound graphics pipeline must have been created with the VK_DYNAMIC_STATE_STENCIL_REFERENCE dynamic state enabled
-
// faceMask must not be 0
ASSERT(faceMask != 0);
- UNIMPLEMENTED("setStencilReference");
+ addCommand<SetStencilReference>(faceMask, reference);
}
void CommandBuffer::bindDescriptorSets(VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout vkLayout,
diff --git a/src/Vulkan/VkCommandBuffer.hpp b/src/Vulkan/VkCommandBuffer.hpp
index 39b4138..0aeeb96 100644
--- a/src/Vulkan/VkCommandBuffer.hpp
+++ b/src/Vulkan/VkCommandBuffer.hpp
@@ -135,6 +135,24 @@
RenderPass* renderPass = nullptr;
Framebuffer* renderPassFramebuffer = nullptr;
std::array<PipelineState, VK_PIPELINE_BIND_POINT_RANGE_SIZE> pipelineState;
+
+ struct DynamicState
+ {
+ VkViewport viewport;
+ VkRect2D scissor;
+ sw::Color<float> blendConstants;
+ float depthBiasConstantFactor = 0.0f;
+ float depthBiasClamp = 0.0f;
+ float depthBiasSlopeFactor = 0.0f;
+ float minDepthBounds = 0.0f;
+ float maxDepthBounds = 0.0f;
+
+ uint32_t compareMask[2] = { 0 };
+ uint32_t writeMask[2] = { 0 };
+ uint32_t reference[2] = { 0 };
+ };
+ DynamicState dynamicState;
+
sw::PushConstantStorage pushConstants;
struct VertexInputBinding
diff --git a/src/Vulkan/VkPipeline.cpp b/src/Vulkan/VkPipeline.cpp
index b9b8610..815923f 100644
--- a/src/Vulkan/VkPipeline.cpp
+++ b/src/Vulkan/VkPipeline.cpp
@@ -231,12 +231,36 @@
{
if(((pCreateInfo->flags & ~(VK_PIPELINE_CREATE_DERIVATIVE_BIT | VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT)) != 0) ||
(pCreateInfo->stageCount != 2) ||
- (pCreateInfo->pTessellationState != nullptr) ||
- (pCreateInfo->pDynamicState != nullptr))
+ (pCreateInfo->pTessellationState != nullptr))
{
UNIMPLEMENTED("pCreateInfo settings");
}
+ if(pCreateInfo->pDynamicState)
+ {
+ for(uint32_t i = 0; i < pCreateInfo->pDynamicState->dynamicStateCount; i++)
+ {
+ VkDynamicState dynamicState = pCreateInfo->pDynamicState->pDynamicStates[i];
+ switch(dynamicState)
+ {
+ case VK_DYNAMIC_STATE_VIEWPORT:
+ case VK_DYNAMIC_STATE_SCISSOR:
+ case VK_DYNAMIC_STATE_LINE_WIDTH:
+ case VK_DYNAMIC_STATE_DEPTH_BIAS:
+ case VK_DYNAMIC_STATE_BLEND_CONSTANTS:
+ case VK_DYNAMIC_STATE_DEPTH_BOUNDS:
+ case VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK:
+ case VK_DYNAMIC_STATE_STENCIL_WRITE_MASK:
+ case VK_DYNAMIC_STATE_STENCIL_REFERENCE:
+ ASSERT(dynamicState < (sizeof(dynamicStateFlags) * 8));
+ dynamicStateFlags |= (1 << dynamicState);
+ break;
+ default:
+ UNIMPLEMENTED("dynamic state");
+ }
+ }
+ }
+
const VkPipelineVertexInputStateCreateInfo* vertexInputState = pCreateInfo->pVertexInputState;
if(vertexInputState->flags != 0)
{
@@ -346,6 +370,7 @@
UNIMPLEMENTED("depthStencilState");
}
+ context.depthBoundsTestEnable = depthStencilState->depthBoundsTestEnable;
context.depthBufferEnable = depthStencilState->depthTestEnable;
context.depthWriteEnable = depthStencilState->depthWriteEnable;
context.depthCompareMode = depthStencilState->depthCompareOp;
@@ -480,6 +505,11 @@
return blendConstants;
}
+bool GraphicsPipeline::hasDynamicState(VkDynamicState dynamicState) const
+{
+ return (dynamicStateFlags & (1 << dynamicState)) != 0;
+}
+
ComputePipeline::ComputePipeline(const VkComputePipelineCreateInfo* pCreateInfo, void* mem)
: Pipeline(Cast(pCreateInfo->layout))
{
diff --git a/src/Vulkan/VkPipeline.hpp b/src/Vulkan/VkPipeline.hpp
index b220027..bf6092a 100644
--- a/src/Vulkan/VkPipeline.hpp
+++ b/src/Vulkan/VkPipeline.hpp
@@ -75,11 +75,13 @@
const VkRect2D& getScissor() const;
const VkViewport& getViewport() const;
const sw::Color<float>& getBlendConstants() const;
+ bool hasDynamicState(VkDynamicState dynamicState) const;
private:
sw::SpirvShader *vertexShader = nullptr;
sw::SpirvShader *fragmentShader = nullptr;
+ uint32_t dynamicStateFlags = 0;
sw::Context context;
VkRect2D scissor;
VkViewport viewport;