1 // Copyright 2020 The SwiftShader Authors. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef vk_Context_hpp 16 #define vk_Context_hpp 17 18 #include "Config.hpp" 19 #include "Memset.hpp" 20 #include "Stream.hpp" 21 #include "System/Types.hpp" 22 #include "Vulkan/VkDescriptorSet.hpp" 23 #include "Vulkan/VkFormat.hpp" 24 25 #include <vector> 26 27 namespace vk { 28 29 class Buffer; 30 class Device; 31 class ImageView; 32 class PipelineLayout; 33 class RenderPass; 34 35 struct VertexInputBinding 36 { 37 Buffer *buffer = nullptr; 38 VkDeviceSize offset = 0; 39 VkDeviceSize size = 0; 40 VkDeviceSize stride = 0; 41 }; 42 43 struct IndexBuffer 44 { getIndexTypevk::IndexBuffer45 inline VkIndexType getIndexType() const { return indexType; } 46 void setIndexBufferBinding(const VertexInputBinding &indexBufferBinding, VkIndexType type); 47 void getIndexBuffers(VkPrimitiveTopology topology, uint32_t count, uint32_t first, bool indexed, bool hasPrimitiveRestartEnable, std::vector<std::pair<uint32_t, void *>> *indexBuffers) const; 48 49 private: 50 uint32_t bytesPerIndex() const; 51 52 VertexInputBinding binding; 53 VkIndexType indexType; 54 }; 55 56 struct Attachments 57 { 58 ImageView *colorBuffer[sw::MAX_COLOR_BUFFERS] = {}; 59 ImageView *depthBuffer = nullptr; 60 ImageView *stencilBuffer = nullptr; 61 62 VkFormat colorFormat(int index) const; 63 VkFormat depthFormat() const; 64 }; 65 66 struct Inputs 67 { 68 void initialize(const VkPipelineVertexInputStateCreateInfo *vertexInputState); 69 70 void updateDescriptorSets(const DescriptorSet::Array &dso, 71 const DescriptorSet::Bindings &ds, 72 const DescriptorSet::DynamicOffsets &ddo); getDescriptorSetObjectsvk::Inputs73 inline const DescriptorSet::Array &getDescriptorSetObjects() const { return descriptorSetObjects; } getDescriptorSetsvk::Inputs74 inline const DescriptorSet::Bindings &getDescriptorSets() const { return descriptorSets; } getDescriptorDynamicOffsetsvk::Inputs75 inline const DescriptorSet::DynamicOffsets &getDescriptorDynamicOffsets() const { return descriptorDynamicOffsets; } getStreamvk::Inputs76 inline const sw::Stream &getStream(uint32_t i) const { return stream[i]; } 77 78 void bindVertexInputs(int firstInstance, bool dynamicInstanceStride); 79 void setVertexInputBinding(const VertexInputBinding vertexInputBindings[]); 80 void advanceInstanceAttributes(bool dynamicInstanceStride); 81 VkDeviceSize getVertexStride(uint32_t i, bool dynamicVertexStride) const; 82 VkDeviceSize getInstanceStride(uint32_t i, bool dynamicVertexStride) const; 83 84 private: 85 VertexInputBinding vertexInputBindings[MAX_VERTEX_INPUT_BINDINGS] = {}; 86 DescriptorSet::Array descriptorSetObjects = {}; 87 DescriptorSet::Bindings descriptorSets = {}; 88 DescriptorSet::DynamicOffsets descriptorDynamicOffsets = {}; 89 sw::Stream stream[sw::MAX_INTERFACE_COMPONENTS / 4]; 90 }; 91 92 struct MultisampleState 93 { 94 bool sampleShadingEnable = false; 95 bool alphaToCoverage = false; 96 97 int sampleCount = 0; 98 unsigned int multiSampleMask = 0; 99 float minSampleShading = 0.0f; 100 101 void set(const VkPipelineMultisampleStateCreateInfo *multisampleState); 102 }; 103 104 struct BlendState : sw::Memset<BlendState> 105 { BlendStatevk::BlendState106 BlendState() 107 : Memset(this, 0) 108 {} 109 BlendStatevk::BlendState110 BlendState(bool alphaBlendEnable, 111 VkBlendFactor sourceBlendFactor, 112 VkBlendFactor destBlendFactor, 113 VkBlendOp blendOperation, 114 VkBlendFactor sourceBlendFactorAlpha, 115 VkBlendFactor destBlendFactorAlpha, 116 VkBlendOp blendOperationAlpha) 117 : Memset(this, 0) 118 , alphaBlendEnable(alphaBlendEnable) 119 , sourceBlendFactor(sourceBlendFactor) 120 , destBlendFactor(destBlendFactor) 121 , blendOperation(blendOperation) 122 , sourceBlendFactorAlpha(sourceBlendFactorAlpha) 123 , destBlendFactorAlpha(destBlendFactorAlpha) 124 , blendOperationAlpha(blendOperationAlpha) 125 {} 126 127 bool alphaBlendEnable; 128 VkBlendFactor sourceBlendFactor; 129 VkBlendFactor destBlendFactor; 130 VkBlendOp blendOperation; 131 VkBlendFactor sourceBlendFactorAlpha; 132 VkBlendFactor destBlendFactorAlpha; 133 VkBlendOp blendOperationAlpha; 134 }; 135 136 struct DynamicState 137 { 138 VkViewport viewport = {}; 139 VkRect2D scissor = {}; 140 sw::float4 blendConstants = {}; 141 float depthBiasConstantFactor = 0.0f; 142 float depthBiasClamp = 0.0f; 143 float depthBiasSlopeFactor = 0.0f; 144 float minDepthBounds = 0.0f; 145 float maxDepthBounds = 0.0f; 146 float lineWidth = 0.0f; 147 148 VkCullModeFlags cullMode = VK_CULL_MODE_NONE; 149 VkBool32 depthBoundsTestEnable = VK_FALSE; 150 VkCompareOp depthCompareOp = VK_COMPARE_OP_NEVER; 151 VkBool32 depthTestEnable = VK_FALSE; 152 VkBool32 depthWriteEnable = VK_FALSE; 153 VkFrontFace frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; 154 VkPrimitiveTopology primitiveTopology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; 155 uint32_t scissorCount = 0; 156 VkRect2D scissors[vk::MAX_VIEWPORTS] = {}; 157 VkStencilFaceFlags faceMask = (VkStencilFaceFlags)0; 158 VkStencilOpState frontStencil = {}; 159 VkStencilOpState backStencil = {}; 160 VkBool32 stencilTestEnable = VK_FALSE; 161 uint32_t viewportCount = 0; 162 VkRect2D viewports[vk::MAX_VIEWPORTS] = {}; 163 VkBool32 rasterizerDiscardEnable = VK_FALSE; 164 VkBool32 depthBiasEnable = VK_FALSE; 165 VkBool32 primitiveRestartEnable = VK_FALSE; 166 }; 167 168 struct VertexInputInterfaceDynamicStateFlags 169 { 170 bool dynamicPrimitiveRestartEnable : 1; 171 bool dynamicPrimitiveTopology : 1; 172 bool dynamicVertexInputBindingStride : 1; 173 }; 174 175 struct PreRasterizationDynamicStateFlags 176 { 177 bool dynamicLineWidth : 1; 178 bool dynamicDepthBias : 1; 179 bool dynamicDepthBiasEnable : 1; 180 bool dynamicCullMode : 1; 181 bool dynamicFrontFace : 1; 182 bool dynamicViewport : 1; 183 bool dynamicScissor : 1; 184 bool dynamicViewportWithCount : 1; 185 bool dynamicScissorWithCount : 1; 186 bool dynamicRasterizerDiscardEnable : 1; 187 }; 188 189 struct FragmentDynamicStateFlags 190 { 191 bool dynamicDepthTestEnable : 1; 192 bool dynamicDepthWriteEnable : 1; 193 bool dynamicDepthBoundsTestEnable : 1; 194 bool dynamicDepthBounds : 1; 195 bool dynamicDepthCompareOp : 1; 196 bool dynamicStencilTestEnable : 1; 197 bool dynamicStencilOp : 1; 198 bool dynamicStencilCompareMask : 1; 199 bool dynamicStencilWriteMask : 1; 200 bool dynamicStencilReference : 1; 201 }; 202 203 struct FragmentOutputInterfaceDynamicStateFlags 204 { 205 bool dynamicBlendConstants : 1; 206 }; 207 208 struct DynamicStateFlags 209 { 210 VertexInputInterfaceDynamicStateFlags vertexInputInterface; 211 PreRasterizationDynamicStateFlags preRasterization; 212 FragmentDynamicStateFlags fragment; 213 FragmentOutputInterfaceDynamicStateFlags fragmentOutputInterface; 214 }; 215 216 struct VertexInputInterfaceState 217 { 218 void initialize(const VkPipelineVertexInputStateCreateInfo *vertexInputState, 219 const VkPipelineInputAssemblyStateCreateInfo *inputAssemblyState, 220 const DynamicStateFlags &allDynamicStateFlags); 221 222 void applyState(const DynamicState &dynamicState); 223 getTopologyvk::VertexInputInterfaceState224 inline VkPrimitiveTopology getTopology() const { return topology; } hasPrimitiveRestartEnablevk::VertexInputInterfaceState225 inline bool hasPrimitiveRestartEnable() const { return primitiveRestartEnable; } 226 hasDynamicVertexStridevk::VertexInputInterfaceState227 inline bool hasDynamicVertexStride() const { return dynamicStateFlags.dynamicVertexInputBindingStride; } hasDynamicTopologyvk::VertexInputInterfaceState228 inline bool hasDynamicTopology() const { return dynamicStateFlags.dynamicPrimitiveTopology; } hasDynamicPrimitiveRestartEnablevk::VertexInputInterfaceState229 inline bool hasDynamicPrimitiveRestartEnable() const { return dynamicStateFlags.dynamicPrimitiveRestartEnable; } 230 231 bool isDrawPoint(bool polygonModeAware, VkPolygonMode polygonMode) const; 232 bool isDrawLine(bool polygonModeAware, VkPolygonMode polygonMode) const; 233 bool isDrawTriangle(bool polygonModeAware, VkPolygonMode polygonMode) const; 234 235 private: 236 VertexInputInterfaceDynamicStateFlags dynamicStateFlags = {}; 237 238 bool primitiveRestartEnable = false; 239 240 VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; 241 }; 242 243 struct PreRasterizationState 244 { 245 void initialize(const vk::Device *device, 246 const PipelineLayout *layout, 247 const VkPipelineViewportStateCreateInfo *viewportState, 248 const VkPipelineRasterizationStateCreateInfo *rasterizationState, 249 const vk::RenderPass *renderPass, uint32_t subpassIndex, 250 const VkPipelineRenderingCreateInfo *rendering, 251 const DynamicStateFlags &allDynamicStateFlags); 252 getPipelineLayoutvk::PreRasterizationState253 inline const PipelineLayout *getPipelineLayout() const { return pipelineLayout; } overridePipelineLayoutvk::PreRasterizationState254 inline void overridePipelineLayout(const PipelineLayout *linkedLayout) { pipelineLayout = linkedLayout; } 255 256 void applyState(const DynamicState &dynamicState); 257 getCullModevk::PreRasterizationState258 inline VkCullModeFlags getCullMode() const { return cullMode; } getFrontFacevk::PreRasterizationState259 inline VkFrontFace getFrontFace() const { return frontFace; } getPolygonModevk::PreRasterizationState260 inline VkPolygonMode getPolygonMode() const { return polygonMode; } getProvokingVertexModevk::PreRasterizationState261 inline VkProvokingVertexModeEXT getProvokingVertexMode() const { return provokingVertexMode; } getLineRasterizationModevk::PreRasterizationState262 inline VkLineRasterizationModeEXT getLineRasterizationMode() const { return lineRasterizationMode; } 263 hasRasterizerDiscardvk::PreRasterizationState264 inline bool hasRasterizerDiscard() const { return rasterizerDiscard; } 265 getConstantDepthBiasvk::PreRasterizationState266 inline float getConstantDepthBias() const { return depthBiasEnable ? constantDepthBias : 0; } getSlopeDepthBiasvk::PreRasterizationState267 inline float getSlopeDepthBias() const { return depthBiasEnable ? slopeDepthBias : 0; } getDepthBiasClampvk::PreRasterizationState268 inline float getDepthBiasClamp() const { return depthBiasEnable ? depthBiasClamp : 0; } 269 hasDepthRangeUnrestrictedvk::PreRasterizationState270 inline bool hasDepthRangeUnrestricted() const { return depthRangeUnrestricted; } getDepthClampEnablevk::PreRasterizationState271 inline bool getDepthClampEnable() const { return depthClampEnable; } getDepthClipEnablevk::PreRasterizationState272 inline bool getDepthClipEnable() const { return depthClipEnable; } getDepthClipNegativeOneToOnevk::PreRasterizationState273 inline bool getDepthClipNegativeOneToOne() const { return depthClipNegativeOneToOne; } 274 getLineWidthvk::PreRasterizationState275 inline float getLineWidth() const { return lineWidth; } 276 getScissorvk::PreRasterizationState277 inline const VkRect2D &getScissor() const { return scissor; } getViewportvk::PreRasterizationState278 inline const VkViewport &getViewport() const { return viewport; } 279 280 private: 281 const PipelineLayout *pipelineLayout = nullptr; 282 283 PreRasterizationDynamicStateFlags dynamicStateFlags = {}; 284 285 bool rasterizerDiscard = false; 286 bool depthClampEnable = false; 287 bool depthClipEnable = false; 288 bool depthClipNegativeOneToOne = false; 289 bool depthBiasEnable = false; 290 bool depthRangeUnrestricted = false; 291 292 VkCullModeFlags cullMode = 0; 293 VkFrontFace frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; 294 VkPolygonMode polygonMode = VK_POLYGON_MODE_FILL; 295 VkProvokingVertexModeEXT provokingVertexMode = VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT; 296 VkLineRasterizationModeEXT lineRasterizationMode = VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT; 297 298 float depthBiasClamp = 0.0f; 299 float constantDepthBias = 0.0f; 300 float slopeDepthBias = 0.0f; 301 302 float lineWidth = 0.0f; 303 304 VkRect2D scissor = {}; 305 VkViewport viewport = {}; 306 }; 307 308 struct FragmentState 309 { 310 void initialize(const PipelineLayout *layout, 311 const VkPipelineDepthStencilStateCreateInfo *depthStencilState, 312 const vk::RenderPass *renderPass, uint32_t subpassIndex, 313 const VkPipelineRenderingCreateInfo *rendering, 314 const DynamicStateFlags &allDynamicStateFlags); 315 getPipelineLayoutvk::FragmentState316 inline const PipelineLayout *getPipelineLayout() const { return pipelineLayout; } overridePipelineLayoutvk::FragmentState317 inline void overridePipelineLayout(const PipelineLayout *linkedLayout) { pipelineLayout = linkedLayout; } 318 319 void applyState(const DynamicState &dynamicState); 320 getFrontStencilvk::FragmentState321 inline VkStencilOpState getFrontStencil() const { return frontStencil; } getBackStencilvk::FragmentState322 inline VkStencilOpState getBackStencil() const { return backStencil; } 323 getMinDepthBoundsvk::FragmentState324 inline float getMinDepthBounds() const { return minDepthBounds; } getMaxDepthBoundsvk::FragmentState325 inline float getMaxDepthBounds() const { return maxDepthBounds; } 326 getDepthCompareModevk::FragmentState327 inline VkCompareOp getDepthCompareMode() const { return depthCompareMode; } 328 329 bool depthWriteActive(const Attachments &attachments) const; 330 bool depthTestActive(const Attachments &attachments) const; 331 bool stencilActive(const Attachments &attachments) const; 332 bool depthBoundsTestActive(const Attachments &attachments) const; 333 334 private: 335 void setDepthStencilState(const VkPipelineDepthStencilStateCreateInfo *depthStencilState); 336 337 const PipelineLayout *pipelineLayout = nullptr; 338 339 FragmentDynamicStateFlags dynamicStateFlags = {}; 340 341 bool depthTestEnable = false; 342 bool depthWriteEnable = false; 343 bool depthBoundsTestEnable = false; 344 bool stencilEnable = false; 345 346 float minDepthBounds = 0.0f; 347 float maxDepthBounds = 0.0f; 348 349 VkCompareOp depthCompareMode = VK_COMPARE_OP_NEVER; 350 351 VkStencilOpState frontStencil = {}; 352 VkStencilOpState backStencil = {}; 353 354 // Note: if a pipeline library is created with the fragment state only, and sample shading 355 // is enabled or a render pass is provided, VkPipelineMultisampleStateCreateInfo must be 356 // provided. This must identically match with the one provided for the fragment output 357 // interface library. 358 // 359 // Currently, SwiftShader can always use the copy provided and stored in 360 // FragmentOutputInterfaceState. If a future optimization requires access to this state in 361 // a pipeline library without fragment output interface, a copy of MultisampleState can be 362 // placed here and initialized under the above condition. 363 // 364 // Ref: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap10.html#pipeline-graphics-subsets 365 }; 366 367 struct FragmentOutputInterfaceState 368 { 369 void initialize(const VkPipelineColorBlendStateCreateInfo *colorBlendState, 370 const VkPipelineMultisampleStateCreateInfo *multisampleState, 371 const vk::RenderPass *renderPass, uint32_t subpassIndex, 372 const VkPipelineRenderingCreateInfo *rendering, 373 const DynamicStateFlags &allDynamicStateFlags); 374 375 void applyState(const DynamicState &dynamicState); 376 getMultiSampleMaskvk::FragmentOutputInterfaceState377 inline unsigned int getMultiSampleMask() const { return multisample.multiSampleMask; } getSampleCountvk::FragmentOutputInterfaceState378 inline int getSampleCount() const { return multisample.sampleCount; } hasSampleShadingEnabledvk::FragmentOutputInterfaceState379 inline bool hasSampleShadingEnabled() const { return multisample.sampleShadingEnable; } getMinSampleShadingvk::FragmentOutputInterfaceState380 inline float getMinSampleShading() const { return multisample.minSampleShading; } hasAlphaToCoveragevk::FragmentOutputInterfaceState381 inline bool hasAlphaToCoverage() const { return multisample.alphaToCoverage; } 382 getBlendConstantsvk::FragmentOutputInterfaceState383 inline const sw::float4 &getBlendConstants() const { return blendConstants; } 384 385 BlendState getBlendState(int index, const Attachments &attachments, bool fragmentContainsKill) const; 386 387 int colorWriteActive(int index, const Attachments &attachments) const; 388 389 private: 390 void setColorBlendState(const VkPipelineColorBlendStateCreateInfo *colorBlendState); 391 392 VkBlendFactor blendFactor(VkBlendOp blendOperation, VkBlendFactor blendFactor) const; 393 VkBlendOp blendOperation(VkBlendOp blendOperation, VkBlendFactor sourceBlendFactor, VkBlendFactor destBlendFactor, vk::Format format) const; 394 395 bool alphaBlendActive(int index, const Attachments &attachments, bool fragmentContainsKill) const; 396 bool colorWriteActive(const Attachments &attachments) const; 397 398 int colorWriteMask[sw::MAX_COLOR_BUFFERS] = {}; // RGBA 399 400 FragmentOutputInterfaceDynamicStateFlags dynamicStateFlags = {}; 401 402 sw::float4 blendConstants = {}; 403 BlendState blendState[sw::MAX_COLOR_BUFFERS] = {}; 404 405 MultisampleState multisample; 406 }; 407 408 struct GraphicsState 409 { 410 GraphicsState(const Device *device, const VkGraphicsPipelineCreateInfo *pCreateInfo, const PipelineLayout *layout); 411 412 GraphicsState combineStates(const DynamicState &dynamicState) const; 413 hasVertexInputInterfaceStatevk::GraphicsState414 bool hasVertexInputInterfaceState() const 415 { 416 return (validSubset & VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT) != 0; 417 } hasPreRasterizationStatevk::GraphicsState418 bool hasPreRasterizationState() const 419 { 420 return (validSubset & VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT) != 0; 421 } hasFragmentStatevk::GraphicsState422 bool hasFragmentState() const 423 { 424 return (validSubset & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT) != 0; 425 } hasFragmentOutputInterfaceStatevk::GraphicsState426 bool hasFragmentOutputInterfaceState() const 427 { 428 return (validSubset & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT) != 0; 429 } 430 getVertexInputInterfaceStatevk::GraphicsState431 const VertexInputInterfaceState &getVertexInputInterfaceState() const 432 { 433 ASSERT(hasVertexInputInterfaceState()); 434 return vertexInputInterfaceState; 435 } getPreRasterizationStatevk::GraphicsState436 const PreRasterizationState &getPreRasterizationState() const 437 { 438 ASSERT(hasPreRasterizationState()); 439 return preRasterizationState; 440 } getFragmentStatevk::GraphicsState441 const FragmentState &getFragmentState() const 442 { 443 ASSERT(hasFragmentState()); 444 return fragmentState; 445 } getFragmentOutputInterfaceStatevk::GraphicsState446 const FragmentOutputInterfaceState &getFragmentOutputInterfaceState() const 447 { 448 ASSERT(hasFragmentOutputInterfaceState()); 449 return fragmentOutputInterfaceState; 450 } 451 452 private: 453 // The four subsets of a graphics pipeline as described in the spec. With 454 // VK_EXT_graphics_pipeline_library, a number of these may be valid. 455 VertexInputInterfaceState vertexInputInterfaceState; 456 PreRasterizationState preRasterizationState; 457 FragmentState fragmentState; 458 FragmentOutputInterfaceState fragmentOutputInterfaceState; 459 460 VkGraphicsPipelineLibraryFlagsEXT validSubset = 0; 461 }; 462 463 } // namespace vk 464 465 #endif // vk_Context_hpp 466