Context refactor: from OpenGL-like state to Vulkan-like state

Overview of the changes: The Context class has been split into more Vulkan related functional elements: - The IndexBuffer class, which contains the index buffer information and has been extended to also the functionality to support primitive restart. Should we need primitive restart related caching in the future, this would be the place to do it. - The Attachments class, which contains information about render targets and depth and stencil buffers - The Inputs class, which contains information about descriptor sets and input streams. - The GraphicsState is a completely constant class which can only be modified in the constructor, which represents the state of a graphics pipeline, which never changes past construction. The GraphicsState can be combined with a DynamicState structure in order to create a complete state used by rendering. Also to note: - The DynamicState class in now in Context.hpp, in order for the GraphicsState to have functionality related to it. - PushConstantStorage was moved to vk::Pipeline, as it is used by both the Graphics Pipeline and the Compute Pipeline. - Viewport/scissor functionality is contained in the GraphicsState and was removed from the Renderer. - All *Processor::update() functions now receive only the information that they require, rather that having access to the entire context. Bug: b/132280877 Change-Id: I74f2582d34e45aa1e7b192dbd2b9b770e7af118d Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/48830Reviewed-by: 's avatarNicolas Capens <nicolascapens@google.com> Tested-by: 's avatarAlexis Hétu <sugoi@google.com> Commit-Queue: Alexis Hétu <sugoi@google.com> Kokoro-Result: kokoro <noreply+kokoro@google.com>
parent d94a77b3
// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
// Copyright 2020 The SwiftShader Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
......@@ -12,33 +12,78 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef sw_Context_hpp
#define sw_Context_hpp
#ifndef vk_Context_hpp
#define vk_Context_hpp
#include "Config.hpp"
#include "Memset.hpp"
#include "Stream.hpp"
#include "System/Types.hpp"
#include "Vulkan/VkConfig.hpp"
#include "Vulkan/VkDescriptorSet.hpp"
#include <vector>
namespace vk {
class Buffer;
class Device;
class ImageView;
class PipelineLayout;
} // namespace vk
struct VertexInputBinding
{
Buffer *buffer;
VkDeviceSize offset;
};
namespace sw {
struct IndexBuffer
{
inline VkIndexType getIndexType() const { return indexType; }
void setIndexBufferBinding(const VertexInputBinding &indexBufferBinding, VkIndexType type);
void getIndexBuffers(VkPrimitiveTopology topology, uint32_t count, uint32_t first, bool indexed, bool hasPrimitiveRestartEnable, std::vector<std::pair<uint32_t, void *>> *indexBuffers) const;
private:
int bytesPerIndex() const;
class SpirvShader;
VertexInputBinding binding;
VkIndexType indexType;
};
struct PushConstantStorage
struct Attachments
{
unsigned char data[vk::MAX_PUSH_CONSTANT_SIZE];
ImageView *renderTarget[sw::RENDERTARGETS] = {};
ImageView *depthBuffer = nullptr;
ImageView *stencilBuffer = nullptr;
bool isColorClamped(int index) const;
VkFormat renderTargetInternalFormat(int index) const;
};
struct Inputs
{
Inputs(const VkPipelineVertexInputStateCreateInfo *vertexInputState);
void updateDescriptorSets(const DescriptorSet::Array &dso,
const DescriptorSet::Bindings &ds,
const DescriptorSet::DynamicOffsets &ddo);
inline const DescriptorSet::Array &getDescriptorSetObjects() const { return descriptorSetObjects; }
inline const DescriptorSet::Bindings &getDescriptorSets() const { return descriptorSets; }
inline const DescriptorSet::DynamicOffsets &getDescriptorDynamicOffsets() const { return descriptorDynamicOffsets; }
inline const sw::Stream &getStream(uint32_t i) const { return stream[i]; }
void bindVertexInputs(int firstInstance);
void setVertexInputBinding(const VertexInputBinding vertexInputBindings[]);
void advanceInstanceAttributes();
private:
VertexInputBinding vertexInputBindings[MAX_VERTEX_INPUT_BINDINGS] = {};
DescriptorSet::Array descriptorSetObjects = {};
DescriptorSet::Bindings descriptorSets = {};
DescriptorSet::DynamicOffsets descriptorDynamicOffsets = {};
sw::Stream stream[sw::MAX_INTERFACE_COMPONENTS / 4];
};
struct BlendState : Memset<BlendState>
struct BlendState : sw::Memset<BlendState>
{
BlendState()
: Memset(this, 0)
......@@ -70,24 +115,93 @@ struct BlendState : Memset<BlendState>
VkBlendOp blendOperationAlpha;
};
class Context
struct DynamicState
{
VkViewport viewport;
VkRect2D scissor;
sw::float4 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 };
};
struct GraphicsState
{
public:
Context() = default;
GraphicsState(const Device *device, const VkGraphicsPipelineCreateInfo *pCreateInfo, const PipelineLayout *layout, bool robustBufferAccess);
const GraphicsState combineStates(const DynamicState &dynamicState) const;
inline const PipelineLayout *getPipelineLayout() const { return pipelineLayout; }
inline bool getRobustBufferAccess() const { return robustBufferAccess; }
inline VkPrimitiveTopology getTopology() const { return topology; }
inline VkProvokingVertexModeEXT getProvokingVertexMode() const { return provokingVertexMode; }
inline VkStencilOpState getFrontStencil() const { return frontStencil; }
inline VkStencilOpState getBackStencil() const { return backStencil; }
// Pixel processor states
inline VkCullModeFlags getCullMode() const { return cullMode; }
inline VkFrontFace getFrontFace() const { return frontFace; }
inline VkPolygonMode getPolygonMode() const { return polygonMode; }
inline VkLineRasterizationModeEXT getLineRasterizationMode() const { return lineRasterizationMode; }
inline float getConstantDepthBias() const { return constantDepthBias; }
inline float getSlopeDepthBias() const { return slopeDepthBias; }
inline float getDepthBiasClamp() const { return depthBiasClamp; }
inline bool hasDepthRangeUnrestricted() const { return depthRangeUnrestricted; }
// Pixel processor states
inline bool hasRasterizerDiscard() const { return rasterizerDiscard; }
inline VkCompareOp getDepthCompareMode() const { return depthCompareMode; }
inline float getLineWidth() const { return lineWidth; }
inline unsigned int getMultiSampleMask() const { return multiSampleMask; }
inline int getSampleCount() const { return sampleCount; }
inline bool hasAlphaToCoverage() const { return alphaToCoverage; }
inline bool hasPrimitiveRestartEnable() const { return primitiveRestartEnable; }
inline const VkRect2D &getScissor() const { return scissor; }
inline const VkViewport &getViewport() const { return viewport; }
inline const sw::float4 &getBlendConstants() const { return blendConstants; }
bool isDrawPoint(bool polygonModeAware) const;
bool isDrawLine(bool polygonModeAware) const;
bool isDrawTriangle(bool polygonModeAware) const;
bool depthWriteActive() const;
bool depthBufferActive() const;
bool stencilActive() const;
BlendState getBlendState(int index, const Attachments &attachments, bool fragmentContainsKill) const;
void setBlendState(int index, BlendState state);
BlendState getBlendState(int index) const;
bool isColorClamped(int index) const;
int colorWriteActive(int index, const Attachments &attachments) const;
bool depthWriteActive(const Attachments &attachments) const;
bool depthBufferActive(const Attachments &attachments) const;
bool stencilActive(const Attachments &attachments) const;
private:
inline bool hasDynamicState(VkDynamicState dynamicState) const { return (dynamicStateFlags & (1 << dynamicState)) != 0; }
VkBlendFactor sourceBlendFactor(int index) const;
VkBlendFactor destBlendFactor(int index) const;
VkBlendOp blendOperation(int index, const Attachments &attachments) const;
VkBlendFactor sourceBlendFactorAlpha(int index) const;
VkBlendFactor destBlendFactorAlpha(int index) const;
VkBlendOp blendOperationAlpha(int index, const Attachments &attachments) const;
bool alphaBlendActive(int index, const Attachments &attachments, bool fragmentContainsKill) const;
bool colorWriteActive(const Attachments &attachments) const;
const PipelineLayout *pipelineLayout;
const bool robustBufferAccess = true;
uint32_t dynamicStateFlags = 0;
VkPrimitiveTopology topology;
VkProvokingVertexModeEXT provokingVertexMode;
bool stencilEnable;
......@@ -105,27 +219,6 @@ public:
float depthBiasClamp;
bool depthRangeUnrestricted;
VkFormat renderTargetInternalFormat(int index) const;
int colorWriteActive(int index) const;
vk::DescriptorSet::Array descriptorSetObjects = {};
vk::DescriptorSet::Bindings descriptorSets = {};
vk::DescriptorSet::DynamicOffsets descriptorDynamicOffsets = {};
Stream input[MAX_INTERFACE_COMPONENTS / 4];
bool robustBufferAccess;
vk::ImageView *renderTarget[RENDERTARGETS];
vk::ImageView *depthBuffer;
vk::ImageView *stencilBuffer;
vk::PipelineLayout const *pipelineLayout;
// Shaders
const SpirvShader *pixelShader;
const SpirvShader *vertexShader;
bool occlusionEnabled;
// Pixel processor states
bool rasterizerDiscard;
bool depthBoundsTestEnable;
......@@ -135,28 +228,19 @@ public:
float lineWidth;
int colorWriteMask[RENDERTARGETS]; // RGBA
unsigned int sampleMask;
int colorWriteMask[sw::RENDERTARGETS]; // RGBA
unsigned int multiSampleMask;
int sampleCount;
bool alphaToCoverage;
private:
bool colorWriteActive() const;
bool colorUsed() const;
bool alphaBlendActive(int index) const;
VkBlendFactor sourceBlendFactor(int index) const;
VkBlendFactor destBlendFactor(int index) const;
VkBlendOp blendOperation(int index) const;
bool primitiveRestartEnable = false;
VkRect2D scissor;
VkViewport viewport;
sw::float4 blendConstants;
VkBlendFactor sourceBlendFactorAlpha(int index) const;
VkBlendFactor destBlendFactorAlpha(int index) const;
VkBlendOp blendOperationAlpha(int index) const;
BlendState blendState[RENDERTARGETS];
BlendState blendState[sw::RENDERTARGETS];
};
} // namespace sw
} // namespace vk
#endif // sw_Context_hpp
#endif // vk_Context_hpp
......@@ -82,17 +82,17 @@ void PixelProcessor::setRoutineCacheSize(int cacheSize)
routineCache = std::make_unique<RoutineCacheType>(clamp(cacheSize, 1, 65536));
}
const PixelProcessor::State PixelProcessor::update(const Context *context) const
const PixelProcessor::State PixelProcessor::update(const vk::GraphicsState &pipelineState, const sw::SpirvShader *fragmentShader, const sw::SpirvShader *vertexShader, const vk::Attachments &attachments, bool occlusionEnabled) const
{
State state;
state.numClipDistances = context->vertexShader->getNumOutputClipDistances();
state.numCullDistances = context->vertexShader->getNumOutputCullDistances();
state.numClipDistances = vertexShader->getNumOutputClipDistances();
state.numCullDistances = vertexShader->getNumOutputCullDistances();
if(context->pixelShader)
if(fragmentShader)
{
state.shaderID = context->pixelShader->getSerialID();
state.pipelineLayoutIdentifier = context->pipelineLayout->identifier;
state.shaderID = fragmentShader->getSerialID();
state.pipelineLayoutIdentifier = pipelineState.getPipelineLayout()->identifier;
}
else
{
......@@ -100,49 +100,50 @@ const PixelProcessor::State PixelProcessor::update(const Context *context) const
state.pipelineLayoutIdentifier = 0;
}
state.alphaToCoverage = context->alphaToCoverage;
state.depthWriteEnable = context->depthWriteActive();
state.alphaToCoverage = pipelineState.hasAlphaToCoverage();
state.depthWriteEnable = pipelineState.depthWriteActive(attachments);
if(context->stencilActive())
if(pipelineState.stencilActive(attachments))
{
state.stencilActive = true;
state.frontStencil = context->frontStencil;
state.backStencil = context->backStencil;
state.frontStencil = pipelineState.getFrontStencil();
state.backStencil = pipelineState.getBackStencil();
}
if(context->depthBufferActive())
if(pipelineState.depthBufferActive(attachments))
{
state.depthTestActive = true;
state.depthCompareMode = context->depthCompareMode;
state.depthFormat = context->depthBuffer->getFormat();
state.depthCompareMode = pipelineState.getDepthCompareMode();
state.depthFormat = attachments.depthBuffer->getFormat();
state.depthBias = (context->constantDepthBias != 0.0f) || (context->slopeDepthBias != 0.0f);
state.depthBias = (pipelineState.getConstantDepthBias() != 0.0f) || (pipelineState.getSlopeDepthBias() != 0.0f);
// "For fixed-point depth buffers, fragment depth values are always limited to the range [0,1] by clamping after depth bias addition is performed.
// Unless the VK_EXT_depth_range_unrestricted extension is enabled, fragment depth values are clamped even when the depth buffer uses a floating-point representation."
state.depthClamp = !state.depthFormat.isFloatFormat() || !context->depthRangeUnrestricted;
state.depthClamp = !state.depthFormat.isFloatFormat() || !pipelineState.hasDepthRangeUnrestricted();
}
state.occlusionEnabled = context->occlusionEnabled;
state.occlusionEnabled = occlusionEnabled;
bool fragmentContainsKill = (fragmentShader && fragmentShader->getModes().ContainsKill);
for(int i = 0; i < RENDERTARGETS; i++)
{
state.colorWriteMask |= context->colorWriteActive(i) << (4 * i);
state.targetFormat[i] = context->renderTargetInternalFormat(i);
state.blendState[i] = context->getBlendState(i);
state.colorWriteMask |= pipelineState.colorWriteActive(i, attachments) << (4 * i);
state.targetFormat[i] = attachments.renderTargetInternalFormat(i);
state.blendState[i] = pipelineState.getBlendState(i, attachments, fragmentContainsKill);
}
state.multiSampleCount = static_cast<unsigned int>(context->sampleCount);
state.multiSampleMask = context->multiSampleMask;
state.multiSampleCount = static_cast<unsigned int>(pipelineState.getSampleCount());
state.multiSampleMask = pipelineState.getMultiSampleMask();
state.enableMultiSampling = (state.multiSampleCount > 1) &&
!(context->isDrawLine(true) && (context->lineRasterizationMode == VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT));
!(pipelineState.isDrawLine(true) && (pipelineState.getLineRasterizationMode() == VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT));
if(state.enableMultiSampling && context->pixelShader)
if(state.enableMultiSampling && fragmentShader)
{
state.centroid = context->pixelShader->getModes().NeedsCentroid;
state.centroid = fragmentShader->getModes().NeedsCentroid;
}
state.frontFace = context->frontFace;
state.frontFace = pipelineState.getFrontFace();
state.hash = state.computeHash();
......@@ -150,8 +151,8 @@ const PixelProcessor::State PixelProcessor::update(const Context *context) const
}
PixelProcessor::RoutineType PixelProcessor::routine(const State &state,
vk::PipelineLayout const *pipelineLayout,
SpirvShader const *pixelShader,
const vk::PipelineLayout *pipelineLayout,
const SpirvShader *pixelShader,
const vk::DescriptorSet::Bindings &descriptorSets)
{
auto routine = routineCache->lookup(state);
......
......@@ -24,11 +24,9 @@
namespace sw {
class PixelShader;
class Rasterizer;
struct Texture;
struct DrawData;
struct Primitive;
class SpirvShader;
using RasterizerFunction = FunctionT<void(const Primitive *primitive, int count, int cluster, int clusterCount, DrawData *draw)>;
......@@ -82,7 +80,7 @@ public:
bool occlusionEnabled;
bool perspective;
BlendState blendState[RENDERTARGETS];
vk::BlendState blendState[RENDERTARGETS];
unsigned int colorWriteMask;
vk::Format targetFormat[RENDERTARGETS];
......@@ -153,9 +151,9 @@ public:
void setBlendConstant(const float4 &blendConstant);
const State update(const Context *context) const;
RoutineType routine(const State &state, vk::PipelineLayout const *pipelineLayout,
SpirvShader const *pixelShader, const vk::DescriptorSet::Bindings &descriptorSets);
const State update(const vk::GraphicsState &pipelineState, const sw::SpirvShader *fragmentShader, const sw::SpirvShader *vertexShader, const vk::Attachments &attachments, bool occlusionEnabled) const;
RoutineType routine(const State &state, const vk::PipelineLayout *pipelineLayout,
const SpirvShader *pixelShader, const vk::DescriptorSet::Bindings &descriptorSets);
void setRoutineCacheSize(int routineCacheSize);
// Other semi-constants
......
......@@ -15,7 +15,6 @@
#ifndef sw_Rasterizer_hpp
#define sw_Rasterizer_hpp
#include "Context.hpp"
#include "PixelProcessor.hpp"
#include "Device/Config.hpp"
......
......@@ -20,8 +20,8 @@
#include "Primitive.hpp"
#include "SetupProcessor.hpp"
#include "VertexProcessor.hpp"
#include "Device/Config.hpp"
#include "Vulkan/VkDescriptorSet.hpp"
#include "Vulkan/VkPipeline.hpp"
#include "marl/finally.h"
#include "marl/pool.h"
......@@ -114,7 +114,7 @@ struct DrawData
float4 a2c2;
float4 a2c3;
PushConstantStorage pushConstants;
vk::Pipeline::PushConstantStorage pushConstants;
};
struct DrawCall
......@@ -209,27 +209,16 @@ public:
bool hasOcclusionQuery() const { return occlusionQuery != nullptr; }
void draw(const sw::Context *context, VkIndexType indexType, unsigned int count, int baseVertex,
void draw(const vk::GraphicsPipeline *pipeline, const vk::DynamicState &dynamicState, unsigned int count, int baseVertex,
CountedEvent *events, int instanceID, int viewID, void *indexBuffer, const VkExtent3D &framebufferExtent,
PushConstantStorage const &pushConstants, bool update = true);
// Viewport & Clipper
void setViewport(const VkViewport &viewport);
void setScissor(const VkRect2D &scissor);
void setBlendConstant(const float4 &blendConstant);
vk::Pipeline::PushConstantStorage const &pushConstants, bool update = true);
void addQuery(vk::Query *query);
void removeQuery(vk::Query *query);
void advanceInstanceAttributes(Stream *inputs);
void synchronize();
private:
VkViewport viewport;
VkRect2D scissor;
DrawCall::Pool drawCallPool;
DrawCall::BatchData::Pool batchDataPool;
......
......@@ -14,7 +14,6 @@
#include "SetupProcessor.hpp"
#include "Context.hpp"
#include "Polygon.hpp"
#include "Primitive.hpp"
#include "Renderer.hpp"
......@@ -56,37 +55,37 @@ SetupProcessor::SetupProcessor()
setRoutineCacheSize(1024);
}
SetupProcessor::State SetupProcessor::update(const sw::Context *context) const
SetupProcessor::State SetupProcessor::update(const vk::GraphicsState &pipelineState, const sw::SpirvShader *fragmentShader, const sw::SpirvShader *vertexShader, const vk::Attachments &attachments) const
{
State state;
bool vPosZW = (context->pixelShader && context->pixelShader->hasBuiltinInput(spv::BuiltInFragCoord));
state.isDrawPoint = context->isDrawPoint(true);
state.isDrawLine = context->isDrawLine(true);
state.isDrawTriangle = context->isDrawTriangle(true);
state.fixedPointDepthBuffer = context->depthBuffer && !context->depthBuffer->getFormat(VK_IMAGE_ASPECT_DEPTH_BIT).isFloatFormat();
state.applyConstantDepthBias = context->isDrawTriangle(false) && (context->constantDepthBias != 0.0f);
state.applySlopeDepthBias = context->isDrawTriangle(false) && (context->slopeDepthBias != 0.0f);
state.applyDepthBiasClamp = context->isDrawTriangle(false) && (context->depthBiasClamp != 0.0f);
state.interpolateZ = context->depthBufferActive() || vPosZW;
state.interpolateW = context->pixelShader != nullptr;
state.frontFace = context->frontFace;
state.cullMode = context->cullMode;
state.multiSampleCount = context->sampleCount;
bool vPosZW = (fragmentShader && fragmentShader->hasBuiltinInput(spv::BuiltInFragCoord));
state.isDrawPoint = pipelineState.isDrawPoint(true);
state.isDrawLine = pipelineState.isDrawLine(true);
state.isDrawTriangle = pipelineState.isDrawTriangle(true);
state.fixedPointDepthBuffer = attachments.depthBuffer && !attachments.depthBuffer->getFormat(VK_IMAGE_ASPECT_DEPTH_BIT).isFloatFormat();
state.applyConstantDepthBias = pipelineState.isDrawTriangle(false) && (pipelineState.getConstantDepthBias() != 0.0f);
state.applySlopeDepthBias = pipelineState.isDrawTriangle(false) && (pipelineState.getSlopeDepthBias() != 0.0f);
state.applyDepthBiasClamp = pipelineState.isDrawTriangle(false) && (pipelineState.getDepthBiasClamp() != 0.0f);
state.interpolateZ = pipelineState.depthBufferActive(attachments) || vPosZW;
state.interpolateW = fragmentShader != nullptr;
state.frontFace = pipelineState.getFrontFace();
state.cullMode = pipelineState.getCullMode();
state.multiSampleCount = pipelineState.getSampleCount();
state.enableMultiSampling = (state.multiSampleCount > 1) &&
!(context->isDrawLine(true) && (context->lineRasterizationMode == VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT));
state.rasterizerDiscard = context->rasterizerDiscard;
!(pipelineState.isDrawLine(true) && (pipelineState.getLineRasterizationMode() == VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT));
state.rasterizerDiscard = pipelineState.hasRasterizerDiscard();
state.numClipDistances = context->vertexShader->getNumOutputClipDistances();
state.numCullDistances = context->vertexShader->getNumOutputCullDistances();
state.numClipDistances = vertexShader->getNumOutputClipDistances();
state.numCullDistances = vertexShader->getNumOutputCullDistances();
if(context->pixelShader)
if(fragmentShader)
{
for(int interpolant = 0; interpolant < MAX_INTERFACE_COMPONENTS; interpolant++)
{
state.gradient[interpolant] = context->pixelShader->inputs[interpolant];
state.gradient[interpolant] = fragmentShader->inputs[interpolant];
}
}
......
......@@ -76,7 +76,7 @@ public:
SetupProcessor();
State update(const sw::Context *context) const;
State update(const vk::GraphicsState &pipelineState, const sw::SpirvShader *fragmentShader, const sw::SpirvShader *vertexShader, const vk::Attachments &attachments) const;
RoutineType routine(const State &state);
void setRoutineCacheSize(int cacheSize);
......
......@@ -65,21 +65,21 @@ void VertexProcessor::setRoutineCacheSize(int cacheSize)
routineCache = std::make_unique<RoutineCacheType>(clamp(cacheSize, 1, 65536));
}
const VertexProcessor::State VertexProcessor::update(const sw::Context *context)
const VertexProcessor::State VertexProcessor::update(const vk::GraphicsState &pipelineState, const sw::SpirvShader *vertexShader, const vk::Inputs &inputs)
{
State state;
state.shaderID = context->vertexShader->getSerialID();
state.pipelineLayoutIdentifier = context->pipelineLayout->identifier;
state.robustBufferAccess = context->robustBufferAccess;
state.isPoint = context->topology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
state.shaderID = vertexShader->getSerialID();
state.pipelineLayoutIdentifier = pipelineState.getPipelineLayout()->identifier;
state.robustBufferAccess = pipelineState.getRobustBufferAccess();
state.isPoint = pipelineState.getTopology() == VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
for(int i = 0; i < MAX_INTERFACE_COMPONENTS / 4; i++)
for(size_t i = 0; i < MAX_INTERFACE_COMPONENTS / 4; i++)
{
state.input[i].format = context->input[i].format;
state.input[i].format = inputs.getStream(i).format;
// TODO: get rid of attribType -- just keep the VK format all the way through, this fully determines
// how to handle the attribute.
state.input[i].attribType = context->vertexShader->inputs[i * 4].Type;
state.input[i].attribType = vertexShader->inputs[i * 4].Type;
}
state.hash = state.computeHash();
......
......@@ -94,7 +94,7 @@ public:
VertexProcessor();
const State update(const sw::Context *context);
const State update(const vk::GraphicsState &pipelineState, const sw::SpirvShader *vertexShader, const vk::Inputs &inputs);
RoutineType routine(const State &state, vk::PipelineLayout const *pipelineLayout,
SpirvShader const *vertexShader, const vk::DescriptorSet::Bindings &descriptorSets);
......
......@@ -209,7 +209,7 @@ void ComputeProgram::run(
vk::DescriptorSet::Array const &descriptorSetObjects,
vk::DescriptorSet::Bindings const &descriptorSets,
vk::DescriptorSet::DynamicOffsets const &descriptorDynamicOffsets,
PushConstantStorage const &pushConstants,
vk::Pipeline::PushConstantStorage const &pushConstants,
uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ,
uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ)
{
......
......@@ -17,9 +17,9 @@
#include "SpirvShader.hpp"
#include "Device/Context.hpp"
#include "Reactor/Coroutine.hpp"
#include "Vulkan/VkDescriptorSet.hpp"
#include "Vulkan/VkPipeline.hpp"
#include <functional>
......@@ -58,7 +58,7 @@ public:
vk::DescriptorSet::Array const &descriptorSetObjects,
vk::DescriptorSet::Bindings const &descriptorSetBindings,
vk::DescriptorSet::DynamicOffsets const &descriptorDynamicOffsets,
PushConstantStorage const &pushConstants,
vk::Pipeline::PushConstantStorage const &pushConstants,
uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ,
uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ);
......@@ -76,7 +76,7 @@ protected:
uint32_t invocationsPerSubgroup; // SPIR-V: "SubgroupSize"
uint32_t subgroupsPerWorkgroup; // SPIR-V: "NumSubgroups"
uint32_t invocationsPerWorkgroup; // Total number of invocations per workgroup.
PushConstantStorage pushConstants;
vk::Pipeline::PushConstantStorage pushConstants;
const Constants *constants;
};
......
......@@ -466,56 +466,6 @@ private:
class CmdDrawBase : public vk::CommandBuffer::Command
{
public:
int bytesPerIndex(vk::CommandBuffer::ExecutionState const &executionState)
{
return executionState.indexType == VK_INDEX_TYPE_UINT16 ? 2 : 4;
}
template<typename T>
void processPrimitiveRestart(T *indexBuffer,
uint32_t count,
vk::GraphicsPipeline *pipeline,
std::vector<std::pair<uint32_t, void *>> &indexBuffers)
{
static const T RestartIndex = static_cast<T>(-1);
T *indexBufferStart = indexBuffer;
uint32_t vertexCount = 0;
for(uint32_t i = 0; i < count; i++)
{
if(indexBuffer[i] == RestartIndex)
{
// Record previous segment
if(vertexCount > 0)
{
uint32_t primitiveCount = pipeline->computePrimitiveCount(vertexCount);
if(primitiveCount > 0)
{
indexBuffers.push_back({ primitiveCount, indexBufferStart });
}
}
vertexCount = 0;
}
else
{
if(vertexCount == 0)
{
indexBufferStart = indexBuffer + i;
}
vertexCount++;
}
}
// Record last segment
if(vertexCount > 0)
{
uint32_t primitiveCount = pipeline->computePrimitiveCount(vertexCount);
if(primitiveCount > 0)
{
indexBuffers.push_back({ primitiveCount, indexBufferStart });
}
}
}
void draw(vk::CommandBuffer::ExecutionState &executionState, bool indexed,
uint32_t count, uint32_t instanceCount, uint32_t first, int32_t vertexOffset, uint32_t firstInstance)
{
......@@ -523,87 +473,21 @@ public:
auto *pipeline = static_cast<vk::GraphicsPipeline *>(pipelineState.pipeline);
sw::Context context = pipeline->getContext();
executionState.bindVertexInputs(context, firstInstance);
context.descriptorSetObjects = pipelineState.descriptorSetObjects;
context.descriptorSets = pipelineState.descriptorSets;
context.descriptorDynamicOffsets = pipelineState.descriptorDynamicOffsets;
// 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))
{
context.constantDepthBias = executionState.dynamicState.depthBiasConstantFactor;
context.slopeDepthBias = executionState.dynamicState.depthBiasSlopeFactor;
context.depthBiasClamp = executionState.dynamicState.depthBiasClamp;
}
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);
UNSUPPORTED("VkPhysicalDeviceFeatures::depthBounds");
}
vk::Attachments &attachments = pipeline->getAttachments();
executionState.bindAttachments(&attachments);
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];
}
vk::Inputs &inputs = pipeline->getInputs();
inputs.updateDescriptorSets(pipelineState.descriptorSetObjects,
pipelineState.descriptorSets,
pipelineState.descriptorDynamicOffsets);
inputs.setVertexInputBinding(executionState.vertexInputBindings);
inputs.bindVertexInputs(firstInstance);
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.bindAttachments(context);
context.occlusionEnabled = executionState.renderer->hasOcclusionQuery();
vk::IndexBuffer &indexBuffer = pipeline->getIndexBuffer();
indexBuffer.setIndexBufferBinding(executionState.indexBufferBinding, executionState.indexType);
std::vector<std::pair<uint32_t, void *>> indexBuffers;
if(indexed)
{
void *indexBuffer = executionState.indexBufferBinding.buffer->getOffsetPointer(
executionState.indexBufferBinding.offset + first * bytesPerIndex(executionState));
if(pipeline->hasPrimitiveRestartEnable())
{
switch(executionState.indexType)
{
case VK_INDEX_TYPE_UINT16:
processPrimitiveRestart(static_cast<uint16_t *>(indexBuffer), count, pipeline, indexBuffers);
break;
case VK_INDEX_TYPE_UINT32:
processPrimitiveRestart(static_cast<uint32_t *>(indexBuffer), count, pipeline, indexBuffers);
break;
default:
UNSUPPORTED("VkIndexType %d", int(executionState.indexType));
}
}
else
{
indexBuffers.push_back({ pipeline->computePrimitiveCount(count), indexBuffer });
}
}
else
{
indexBuffers.push_back({ pipeline->computePrimitiveCount(count), nullptr });
}
pipeline->getIndexBuffers(count, first, indexed, &indexBuffers);
for(uint32_t instance = firstInstance; instance != firstInstance + instanceCount; instance++)
{
......@@ -616,14 +500,14 @@ public:
for(auto indexBuffer : indexBuffers)
{
executionState.renderer->draw(&context, executionState.indexType, indexBuffer.first, vertexOffset,
executionState.renderer->draw(pipeline, executionState.dynamicState, indexBuffer.first, vertexOffset,
executionState.events, instance, viewID, indexBuffer.second,
executionState.renderPassFramebuffer->getExtent(),
executionState.pushConstants);
}
}
executionState.renderer->advanceInstanceAttributes(context.input);
inputs.advanceInstanceAttributes();
}
}
};
......@@ -1840,25 +1724,7 @@ void CommandBuffer::submitSecondary(CommandBuffer::ExecutionState &executionStat
}
}
void CommandBuffer::ExecutionState::bindVertexInputs(sw::Context &context, int firstInstance)
{
for(uint32_t i = 0; i < MAX_VERTEX_INPUT_BINDINGS; i++)
{
auto &attrib = context.input[i];
if(attrib.format != VK_FORMAT_UNDEFINED)
{
const auto &vertexInput = vertexInputBindings[attrib.binding];
VkDeviceSize offset = attrib.offset + vertexInput.offset +
attrib.instanceStride * firstInstance;
attrib.buffer = vertexInput.buffer ? vertexInput.buffer->getOffsetPointer(offset) : nullptr;
VkDeviceSize size = vertexInput.buffer ? vertexInput.buffer->getSize() : 0;
attrib.robustnessSize = (size > offset) ? size - offset : 0;
}
}
}
void CommandBuffer::ExecutionState::bindAttachments(sw::Context &context)
void CommandBuffer::ExecutionState::bindAttachments(Attachments *attachments)
{
// Binds all the attachments for the current subpass
// Ideally this would be performed by BeginRenderPass and NextSubpass, but
......@@ -1872,7 +1738,7 @@ void CommandBuffer::ExecutionState::bindAttachments(sw::Context &context)
auto attachmentReference = subpass.pColorAttachments[i];
if(attachmentReference.attachment != VK_ATTACHMENT_UNUSED)
{
context.renderTarget[i] = renderPassFramebuffer->getAttachment(attachmentReference.attachment);
attachments->renderTarget[i] = renderPassFramebuffer->getAttachment(attachmentReference.attachment);
}
}
......@@ -1882,11 +1748,11 @@ void CommandBuffer::ExecutionState::bindAttachments(sw::Context &context)
auto attachment = renderPassFramebuffer->getAttachment(attachmentReference->attachment);
if(attachment->hasDepthAspect())
{
context.depthBuffer = attachment;
attachments->depthBuffer = attachment;
}
if(attachment->hasStencilAspect())
{
context.stencilBuffer = attachment;
attachments->stencilBuffer = attachment;
}
}
}
......
......@@ -17,8 +17,7 @@
#include "VkConfig.hpp"
#include "VkDescriptorSet.hpp"
#include "VkObject.hpp"
#include "Device/Context.hpp"
#include "VkPipeline.hpp"
#include "System/Synchronization.hpp"
#include <memory>
......@@ -155,38 +154,17 @@ public:
Framebuffer *renderPassFramebuffer = nullptr;
std::array<PipelineState, vk::VK_PIPELINE_BIND_POINT_RANGE_SIZE> pipelineState;
struct DynamicState
{
VkViewport viewport;
VkRect2D scissor;
sw::float4 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;
vk::DynamicState dynamicState;
sw::PushConstantStorage pushConstants;
vk::Pipeline::PushConstantStorage pushConstants;
struct VertexInputBinding
{
Buffer *buffer;
VkDeviceSize offset;
};
VertexInputBinding vertexInputBindings[MAX_VERTEX_INPUT_BINDINGS] = {};
VertexInputBinding indexBufferBinding;
VkIndexType indexType;
uint32_t subpassIndex = 0;
void bindAttachments(sw::Context &context);
void bindVertexInputs(sw::Context &context, int firstInstance);
void bindAttachments(Attachments *attachments);
};
void submit(CommandBuffer::ExecutionState &executionState);
......
......@@ -15,9 +15,7 @@
#ifndef VK_PIPELINE_HPP_
#define VK_PIPELINE_HPP_
#include "VkObject.hpp"
#include "Device/Renderer.hpp"
#include "Vulkan/VkDescriptorSet.hpp"
#include "Device/Context.hpp"
#include "Vulkan/VkPipelineCache.hpp"
#include <memory>
......@@ -34,10 +32,7 @@ namespace dbg {
class Context;
} // namespace dbg
class PipelineCache;
class PipelineLayout;
class ShaderModule;
class Device;
class Pipeline
{
......@@ -67,6 +62,11 @@ public:
return layout;
}
struct PushConstantStorage
{
unsigned char data[vk::MAX_PUSH_CONSTANT_SIZE];
};
protected:
PipelineLayout *layout = nullptr;
Device *const device;
......@@ -95,26 +95,31 @@ public:
void compileShaders(const VkAllocationCallbacks *pAllocator, const VkGraphicsPipelineCreateInfo *pCreateInfo, PipelineCache *pipelineCache);
uint32_t computePrimitiveCount(uint32_t vertexCount) const;
const sw::Context &getContext() const;
const VkRect2D &getScissor() const;
const VkViewport &getViewport() const;
const sw::float4 &getBlendConstants() const;
bool hasDynamicState(VkDynamicState dynamicState) const;
bool hasPrimitiveRestartEnable() const { return primitiveRestartEnable; }
const GraphicsState getState(const DynamicState &ds) const { return state.combineStates(ds); }
void getIndexBuffers(uint32_t count, uint32_t first, bool indexed, std::vector<std::pair<uint32_t, void *>> *indexBuffers) const;
IndexBuffer &getIndexBuffer() { return indexBuffer; }
const IndexBuffer &getIndexBuffer() const { return indexBuffer; }
Attachments &getAttachments() { return attachments; }
const Attachments &getAttachments() const { return attachments; }
Inputs &getInputs() { return inputs; }
const Inputs &getInputs() const { return inputs; }
bool containsImageWrite() const;
const std::shared_ptr<sw::SpirvShader> getShader(const VkShaderStageFlagBits &stage) const;
private:
void setShader(const VkShaderStageFlagBits &stage, const std::shared_ptr<sw::SpirvShader> spirvShader);
const std::shared_ptr<sw::SpirvShader> getShader(const VkShaderStageFlagBits &stage) const;
std::shared_ptr<sw::SpirvShader> vertexShader;
std::shared_ptr<sw::SpirvShader> fragmentShader;
uint32_t dynamicStateFlags = 0;
bool primitiveRestartEnable = false;
sw::Context context;
VkRect2D scissor;
VkViewport viewport;
sw::float4 blendConstants;
const GraphicsState state;
IndexBuffer indexBuffer;
Attachments attachments;
Inputs inputs;
};
class ComputePipeline : public Pipeline, public ObjectBase<ComputePipeline, VkPipeline>
......@@ -141,7 +146,7 @@ public:
vk::DescriptorSet::Array const &descriptorSetObjects,
vk::DescriptorSet::Bindings const &descriptorSets,
vk::DescriptorSet::DynamicOffsets const &descriptorDynamicOffsets,
sw::PushConstantStorage const &pushConstants);
vk::Pipeline::PushConstantStorage const &pushConstants);
protected:
std::shared_ptr<sw::SpirvShader> shader;
......
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