| // 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. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef vk_Context_hpp |
| #define vk_Context_hpp |
| |
| #include "Config.hpp" |
| #include "Memset.hpp" |
| #include "Stream.hpp" |
| #include "System/Types.hpp" |
| #include "Vulkan/VkDescriptorSet.hpp" |
| #include "Vulkan/VkFormat.hpp" |
| |
| #include <vector> |
| |
| namespace vk { |
| |
| class Buffer; |
| class Device; |
| class ImageView; |
| class PipelineLayout; |
| class RenderPass; |
| |
| struct VertexInputBinding |
| { |
| Buffer *buffer = nullptr; |
| VkDeviceSize offset = 0; |
| VkDeviceSize size = 0; |
| VkDeviceSize stride = 0; |
| }; |
| |
| 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; |
| |
| VertexInputBinding binding; |
| VkIndexType indexType; |
| }; |
| |
| struct Attachments |
| { |
| ImageView *colorBuffer[sw::MAX_COLOR_BUFFERS] = {}; |
| ImageView *depthBuffer = nullptr; |
| ImageView *stencilBuffer = nullptr; |
| |
| VkFormat colorFormat(int index) const; |
| VkFormat depthFormat() const; |
| }; |
| |
| struct Inputs |
| { |
| void initialize(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, bool dynamicInstanceStride); |
| void setVertexInputBinding(const VertexInputBinding vertexInputBindings[]); |
| void advanceInstanceAttributes(bool dynamicInstanceStride); |
| VkDeviceSize getVertexStride(uint32_t i, bool dynamicVertexStride) const; |
| VkDeviceSize getInstanceStride(uint32_t i, bool dynamicVertexStride) const; |
| |
| 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 MultisampleState |
| { |
| bool sampleShadingEnable = false; |
| bool alphaToCoverage = false; |
| |
| int sampleCount = 0; |
| unsigned int multiSampleMask = 0; |
| float minSampleShading = 0.0f; |
| |
| void set(const VkPipelineMultisampleStateCreateInfo *multisampleState); |
| }; |
| |
| struct BlendState : sw::Memset<BlendState> |
| { |
| BlendState() |
| : Memset(this, 0) |
| {} |
| |
| BlendState(bool alphaBlendEnable, |
| VkBlendFactor sourceBlendFactor, |
| VkBlendFactor destBlendFactor, |
| VkBlendOp blendOperation, |
| VkBlendFactor sourceBlendFactorAlpha, |
| VkBlendFactor destBlendFactorAlpha, |
| VkBlendOp blendOperationAlpha) |
| : Memset(this, 0) |
| , alphaBlendEnable(alphaBlendEnable) |
| , sourceBlendFactor(sourceBlendFactor) |
| , destBlendFactor(destBlendFactor) |
| , blendOperation(blendOperation) |
| , sourceBlendFactorAlpha(sourceBlendFactorAlpha) |
| , destBlendFactorAlpha(destBlendFactorAlpha) |
| , blendOperationAlpha(blendOperationAlpha) |
| {} |
| |
| bool alphaBlendEnable; |
| VkBlendFactor sourceBlendFactor; |
| VkBlendFactor destBlendFactor; |
| VkBlendOp blendOperation; |
| VkBlendFactor sourceBlendFactorAlpha; |
| VkBlendFactor destBlendFactorAlpha; |
| VkBlendOp blendOperationAlpha; |
| }; |
| |
| 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; |
| float lineWidth = 0.0f; |
| |
| VkCullModeFlags cullMode = VK_CULL_MODE_NONE; |
| VkBool32 depthBoundsTestEnable = VK_FALSE; |
| VkCompareOp depthCompareOp = VK_COMPARE_OP_NEVER; |
| VkBool32 depthTestEnable = VK_FALSE; |
| VkBool32 depthWriteEnable = VK_FALSE; |
| VkFrontFace frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; |
| VkPrimitiveTopology primitiveTopology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; |
| uint32_t scissorCount = 0; |
| VkRect2D scissors[vk::MAX_VIEWPORTS] = {}; |
| VkStencilFaceFlags faceMask = (VkStencilFaceFlags)0; |
| VkStencilOpState frontStencil = {}; |
| VkStencilOpState backStencil = {}; |
| VkBool32 stencilTestEnable = VK_FALSE; |
| uint32_t viewportCount = 0; |
| VkRect2D viewports[vk::MAX_VIEWPORTS] = {}; |
| VkBool32 rasterizerDiscardEnable = VK_FALSE; |
| VkBool32 depthBiasEnable = VK_FALSE; |
| VkBool32 primitiveRestartEnable = VK_FALSE; |
| }; |
| |
| struct VertexInputInterfaceDynamicStateFlags |
| { |
| bool dynamicPrimitiveRestartEnable : 1; |
| bool dynamicPrimitiveTopology : 1; |
| bool dynamicVertexInputBindingStride : 1; |
| }; |
| |
| struct PreRasterizationDynamicStateFlags |
| { |
| bool dynamicLineWidth : 1; |
| bool dynamicDepthBias : 1; |
| bool dynamicDepthBiasEnable : 1; |
| bool dynamicCullMode : 1; |
| bool dynamicFrontFace : 1; |
| bool dynamicViewport : 1; |
| bool dynamicScissor : 1; |
| bool dynamicViewportWithCount : 1; |
| bool dynamicScissorWithCount : 1; |
| bool dynamicRasterizerDiscardEnable : 1; |
| }; |
| |
| struct FragmentDynamicStateFlags |
| { |
| bool dynamicDepthTestEnable : 1; |
| bool dynamicDepthWriteEnable : 1; |
| bool dynamicDepthBoundsTestEnable : 1; |
| bool dynamicDepthBounds : 1; |
| bool dynamicDepthCompareOp : 1; |
| bool dynamicStencilTestEnable : 1; |
| bool dynamicStencilOp : 1; |
| bool dynamicStencilCompareMask : 1; |
| bool dynamicStencilWriteMask : 1; |
| bool dynamicStencilReference : 1; |
| }; |
| |
| struct FragmentOutputInterfaceDynamicStateFlags |
| { |
| bool dynamicBlendConstants : 1; |
| }; |
| |
| struct DynamicStateFlags |
| { |
| VertexInputInterfaceDynamicStateFlags vertexInputInterface; |
| PreRasterizationDynamicStateFlags preRasterization; |
| FragmentDynamicStateFlags fragment; |
| FragmentOutputInterfaceDynamicStateFlags fragmentOutputInterface; |
| }; |
| |
| struct VertexInputInterfaceState |
| { |
| void initialize(const VkPipelineVertexInputStateCreateInfo *vertexInputState, |
| const VkPipelineInputAssemblyStateCreateInfo *inputAssemblyState, |
| const DynamicStateFlags &allDynamicStateFlags); |
| |
| void applyState(const DynamicState &dynamicState); |
| |
| inline VkPrimitiveTopology getTopology() const { return topology; } |
| inline bool hasPrimitiveRestartEnable() const { return primitiveRestartEnable; } |
| |
| inline bool hasDynamicVertexStride() const { return dynamicStateFlags.dynamicVertexInputBindingStride; } |
| inline bool hasDynamicTopology() const { return dynamicStateFlags.dynamicPrimitiveTopology; } |
| inline bool hasDynamicPrimitiveRestartEnable() const { return dynamicStateFlags.dynamicPrimitiveRestartEnable; } |
| |
| bool isDrawPoint(bool polygonModeAware, VkPolygonMode polygonMode) const; |
| bool isDrawLine(bool polygonModeAware, VkPolygonMode polygonMode) const; |
| bool isDrawTriangle(bool polygonModeAware, VkPolygonMode polygonMode) const; |
| |
| private: |
| VertexInputInterfaceDynamicStateFlags dynamicStateFlags = {}; |
| |
| bool primitiveRestartEnable = false; |
| |
| VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; |
| }; |
| |
| struct PreRasterizationState |
| { |
| void initialize(const vk::Device *device, |
| const PipelineLayout *layout, |
| const VkPipelineViewportStateCreateInfo *viewportState, |
| const VkPipelineRasterizationStateCreateInfo *rasterizationState, |
| const vk::RenderPass *renderPass, uint32_t subpassIndex, |
| const VkPipelineRenderingCreateInfo *rendering, |
| const DynamicStateFlags &allDynamicStateFlags); |
| |
| inline const PipelineLayout *getPipelineLayout() const { return pipelineLayout; } |
| inline void overridePipelineLayout(const PipelineLayout *linkedLayout) { pipelineLayout = linkedLayout; } |
| |
| void applyState(const DynamicState &dynamicState); |
| |
| inline VkCullModeFlags getCullMode() const { return cullMode; } |
| inline VkFrontFace getFrontFace() const { return frontFace; } |
| inline VkPolygonMode getPolygonMode() const { return polygonMode; } |
| inline VkProvokingVertexModeEXT getProvokingVertexMode() const { return provokingVertexMode; } |
| inline VkLineRasterizationModeEXT getLineRasterizationMode() const { return lineRasterizationMode; } |
| |
| inline bool hasRasterizerDiscard() const { return rasterizerDiscard; } |
| |
| inline float getConstantDepthBias() const { return depthBiasEnable ? constantDepthBias : 0; } |
| inline float getSlopeDepthBias() const { return depthBiasEnable ? slopeDepthBias : 0; } |
| inline float getDepthBiasClamp() const { return depthBiasEnable ? depthBiasClamp : 0; } |
| |
| inline bool hasDepthRangeUnrestricted() const { return depthRangeUnrestricted; } |
| inline bool getDepthClampEnable() const { return depthClampEnable; } |
| inline bool getDepthClipEnable() const { return depthClipEnable; } |
| inline bool getDepthClipNegativeOneToOne() const { return depthClipNegativeOneToOne; } |
| |
| inline float getLineWidth() const { return lineWidth; } |
| |
| inline const VkRect2D &getScissor() const { return scissor; } |
| inline const VkViewport &getViewport() const { return viewport; } |
| |
| private: |
| const PipelineLayout *pipelineLayout = nullptr; |
| |
| PreRasterizationDynamicStateFlags dynamicStateFlags = {}; |
| |
| bool rasterizerDiscard = false; |
| bool depthClampEnable = false; |
| bool depthClipEnable = false; |
| bool depthClipNegativeOneToOne = false; |
| bool depthBiasEnable = false; |
| bool depthRangeUnrestricted = false; |
| |
| VkCullModeFlags cullMode = 0; |
| VkFrontFace frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; |
| VkPolygonMode polygonMode = VK_POLYGON_MODE_FILL; |
| VkProvokingVertexModeEXT provokingVertexMode = VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT; |
| VkLineRasterizationModeEXT lineRasterizationMode = VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT; |
| |
| float depthBiasClamp = 0.0f; |
| float constantDepthBias = 0.0f; |
| float slopeDepthBias = 0.0f; |
| |
| float lineWidth = 0.0f; |
| |
| VkRect2D scissor = {}; |
| VkViewport viewport = {}; |
| }; |
| |
| struct FragmentState |
| { |
| void initialize(const PipelineLayout *layout, |
| const VkPipelineDepthStencilStateCreateInfo *depthStencilState, |
| const vk::RenderPass *renderPass, uint32_t subpassIndex, |
| const VkPipelineRenderingCreateInfo *rendering, |
| const DynamicStateFlags &allDynamicStateFlags); |
| |
| inline const PipelineLayout *getPipelineLayout() const { return pipelineLayout; } |
| inline void overridePipelineLayout(const PipelineLayout *linkedLayout) { pipelineLayout = linkedLayout; } |
| |
| void applyState(const DynamicState &dynamicState); |
| |
| inline VkStencilOpState getFrontStencil() const { return frontStencil; } |
| inline VkStencilOpState getBackStencil() const { return backStencil; } |
| |
| inline float getMinDepthBounds() const { return minDepthBounds; } |
| inline float getMaxDepthBounds() const { return maxDepthBounds; } |
| |
| inline VkCompareOp getDepthCompareMode() const { return depthCompareMode; } |
| |
| bool depthWriteActive(const Attachments &attachments) const; |
| bool depthTestActive(const Attachments &attachments) const; |
| bool stencilActive(const Attachments &attachments) const; |
| bool depthBoundsTestActive(const Attachments &attachments) const; |
| |
| private: |
| void setDepthStencilState(const VkPipelineDepthStencilStateCreateInfo *depthStencilState); |
| |
| const PipelineLayout *pipelineLayout = nullptr; |
| |
| FragmentDynamicStateFlags dynamicStateFlags = {}; |
| |
| bool depthTestEnable = false; |
| bool depthWriteEnable = false; |
| bool depthBoundsTestEnable = false; |
| bool stencilEnable = false; |
| |
| float minDepthBounds = 0.0f; |
| float maxDepthBounds = 0.0f; |
| |
| VkCompareOp depthCompareMode = VK_COMPARE_OP_NEVER; |
| |
| VkStencilOpState frontStencil = {}; |
| VkStencilOpState backStencil = {}; |
| |
| // Note: if a pipeline library is created with the fragment state only, and sample shading |
| // is enabled or a render pass is provided, VkPipelineMultisampleStateCreateInfo must be |
| // provided. This must identically match with the one provided for the fragment output |
| // interface library. |
| // |
| // Currently, SwiftShader can always use the copy provided and stored in |
| // FragmentOutputInterfaceState. If a future optimization requires access to this state in |
| // a pipeline library without fragment output interface, a copy of MultisampleState can be |
| // placed here and initialized under the above condition. |
| // |
| // Ref: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap10.html#pipeline-graphics-subsets |
| }; |
| |
| struct FragmentOutputInterfaceState |
| { |
| void initialize(const VkPipelineColorBlendStateCreateInfo *colorBlendState, |
| const VkPipelineMultisampleStateCreateInfo *multisampleState, |
| const vk::RenderPass *renderPass, uint32_t subpassIndex, |
| const VkPipelineRenderingCreateInfo *rendering, |
| const DynamicStateFlags &allDynamicStateFlags); |
| |
| void applyState(const DynamicState &dynamicState); |
| |
| inline unsigned int getMultiSampleMask() const { return multisample.multiSampleMask; } |
| inline int getSampleCount() const { return multisample.sampleCount; } |
| inline bool hasSampleShadingEnabled() const { return multisample.sampleShadingEnable; } |
| inline float getMinSampleShading() const { return multisample.minSampleShading; } |
| inline bool hasAlphaToCoverage() const { return multisample.alphaToCoverage; } |
| |
| inline const sw::float4 &getBlendConstants() const { return blendConstants; } |
| |
| BlendState getBlendState(int index, const Attachments &attachments, bool fragmentContainsKill) const; |
| |
| int colorWriteActive(int index, const Attachments &attachments) const; |
| |
| private: |
| void setColorBlendState(const VkPipelineColorBlendStateCreateInfo *colorBlendState); |
| |
| VkBlendFactor blendFactor(VkBlendOp blendOperation, VkBlendFactor blendFactor) const; |
| VkBlendOp blendOperation(VkBlendOp blendOperation, VkBlendFactor sourceBlendFactor, VkBlendFactor destBlendFactor, vk::Format format) const; |
| |
| bool alphaBlendActive(int index, const Attachments &attachments, bool fragmentContainsKill) const; |
| bool colorWriteActive(const Attachments &attachments) const; |
| |
| int colorWriteMask[sw::MAX_COLOR_BUFFERS] = {}; // RGBA |
| |
| FragmentOutputInterfaceDynamicStateFlags dynamicStateFlags = {}; |
| |
| sw::float4 blendConstants = {}; |
| BlendState blendState[sw::MAX_COLOR_BUFFERS] = {}; |
| |
| MultisampleState multisample; |
| }; |
| |
| struct GraphicsState |
| { |
| GraphicsState(const Device *device, const VkGraphicsPipelineCreateInfo *pCreateInfo, const PipelineLayout *layout); |
| |
| GraphicsState combineStates(const DynamicState &dynamicState) const; |
| |
| bool hasVertexInputInterfaceState() const |
| { |
| return (validSubset & VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT) != 0; |
| } |
| bool hasPreRasterizationState() const |
| { |
| return (validSubset & VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT) != 0; |
| } |
| bool hasFragmentState() const |
| { |
| return (validSubset & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT) != 0; |
| } |
| bool hasFragmentOutputInterfaceState() const |
| { |
| return (validSubset & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT) != 0; |
| } |
| |
| const VertexInputInterfaceState &getVertexInputInterfaceState() const |
| { |
| ASSERT(hasVertexInputInterfaceState()); |
| return vertexInputInterfaceState; |
| } |
| const PreRasterizationState &getPreRasterizationState() const |
| { |
| ASSERT(hasPreRasterizationState()); |
| return preRasterizationState; |
| } |
| const FragmentState &getFragmentState() const |
| { |
| ASSERT(hasFragmentState()); |
| return fragmentState; |
| } |
| const FragmentOutputInterfaceState &getFragmentOutputInterfaceState() const |
| { |
| ASSERT(hasFragmentOutputInterfaceState()); |
| return fragmentOutputInterfaceState; |
| } |
| |
| private: |
| // The four subsets of a graphics pipeline as described in the spec. With |
| // VK_EXT_graphics_pipeline_library, a number of these may be valid. |
| VertexInputInterfaceState vertexInputInterfaceState; |
| PreRasterizationState preRasterizationState; |
| FragmentState fragmentState; |
| FragmentOutputInterfaceState fragmentOutputInterfaceState; |
| |
| VkGraphicsPipelineLibraryFlagsEXT validSubset = 0; |
| }; |
| |
| } // namespace vk |
| |
| #endif // vk_Context_hpp |