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 InputsDynamicStateFlags 36 { 37 bool dynamicVertexInputBindingStride : 1; 38 bool dynamicVertexInput : 1; 39 }; 40 41 // Note: The split between Inputs and VertexInputInterfaceState is mostly superficial. The state 42 // (be it dynamic or static) in Inputs should have been mostly a part of VertexInputInterfaceState. 43 // Changing that requires some surgery. 44 struct VertexInputInterfaceDynamicStateFlags 45 { 46 bool dynamicPrimitiveRestartEnable : 1; 47 bool dynamicPrimitiveTopology : 1; 48 }; 49 50 struct PreRasterizationDynamicStateFlags 51 { 52 bool dynamicLineWidth : 1; 53 bool dynamicDepthBias : 1; 54 bool dynamicDepthBiasEnable : 1; 55 bool dynamicCullMode : 1; 56 bool dynamicFrontFace : 1; 57 bool dynamicViewport : 1; 58 bool dynamicScissor : 1; 59 bool dynamicViewportWithCount : 1; 60 bool dynamicScissorWithCount : 1; 61 bool dynamicRasterizerDiscardEnable : 1; 62 }; 63 64 struct FragmentDynamicStateFlags 65 { 66 bool dynamicDepthTestEnable : 1; 67 bool dynamicDepthWriteEnable : 1; 68 bool dynamicDepthBoundsTestEnable : 1; 69 bool dynamicDepthBounds : 1; 70 bool dynamicDepthCompareOp : 1; 71 bool dynamicStencilTestEnable : 1; 72 bool dynamicStencilOp : 1; 73 bool dynamicStencilCompareMask : 1; 74 bool dynamicStencilWriteMask : 1; 75 bool dynamicStencilReference : 1; 76 }; 77 78 struct FragmentOutputInterfaceDynamicStateFlags 79 { 80 bool dynamicBlendConstants : 1; 81 }; 82 83 struct DynamicStateFlags 84 { 85 // Note: InputsDynamicStateFlags is kept local to Inputs 86 VertexInputInterfaceDynamicStateFlags vertexInputInterface; 87 PreRasterizationDynamicStateFlags preRasterization; 88 FragmentDynamicStateFlags fragment; 89 FragmentOutputInterfaceDynamicStateFlags fragmentOutputInterface; 90 }; 91 92 struct VertexInputBinding 93 { 94 Buffer *buffer = nullptr; 95 VkDeviceSize offset = 0; 96 VkDeviceSize size = 0; 97 }; 98 99 struct IndexBuffer 100 { getIndexTypevk::IndexBuffer101 inline VkIndexType getIndexType() const { return indexType; } 102 void setIndexBufferBinding(const VertexInputBinding &indexBufferBinding, VkIndexType type); 103 void getIndexBuffers(VkPrimitiveTopology topology, uint32_t count, uint32_t first, bool indexed, bool hasPrimitiveRestartEnable, std::vector<std::pair<uint32_t, void *>> *indexBuffers) const; 104 105 private: 106 uint32_t bytesPerIndex() const; 107 108 VertexInputBinding binding; 109 VkIndexType indexType; 110 }; 111 112 struct Attachments 113 { 114 ImageView *colorBuffer[sw::MAX_COLOR_BUFFERS] = {}; 115 ImageView *depthBuffer = nullptr; 116 ImageView *stencilBuffer = nullptr; 117 118 VkFormat colorFormat(int index) const; 119 VkFormat depthFormat() const; 120 }; 121 122 struct DynamicState; 123 struct Inputs 124 { 125 void initialize(const VkPipelineVertexInputStateCreateInfo *vertexInputState, const VkPipelineDynamicStateCreateInfo *dynamicStateCreateInfo); 126 127 void updateDescriptorSets(const DescriptorSet::Array &dso, 128 const DescriptorSet::Bindings &ds, 129 const DescriptorSet::DynamicOffsets &ddo); getDescriptorSetObjectsvk::Inputs130 inline const DescriptorSet::Array &getDescriptorSetObjects() const { return descriptorSetObjects; } getDescriptorSetsvk::Inputs131 inline const DescriptorSet::Bindings &getDescriptorSets() const { return descriptorSets; } getDescriptorDynamicOffsetsvk::Inputs132 inline const DescriptorSet::DynamicOffsets &getDescriptorDynamicOffsets() const { return descriptorDynamicOffsets; } getStreamvk::Inputs133 inline const sw::Stream &getStream(uint32_t i) const { return stream[i]; } 134 135 void bindVertexInputs(int firstInstance); 136 void setVertexInputBinding(const VertexInputBinding vertexInputBindings[], const DynamicState &dynamicState); 137 void advanceInstanceAttributes(); 138 VkDeviceSize getVertexStride(uint32_t i) const; 139 VkDeviceSize getInstanceStride(uint32_t i) const; 140 141 private: 142 InputsDynamicStateFlags dynamicStateFlags = {}; 143 VertexInputBinding vertexInputBindings[MAX_VERTEX_INPUT_BINDINGS] = {}; 144 DescriptorSet::Array descriptorSetObjects = {}; 145 DescriptorSet::Bindings descriptorSets = {}; 146 DescriptorSet::DynamicOffsets descriptorDynamicOffsets = {}; 147 sw::Stream stream[sw::MAX_INTERFACE_COMPONENTS / 4]; 148 }; 149 150 struct MultisampleState 151 { 152 bool sampleShadingEnable = false; 153 bool alphaToCoverage = false; 154 155 int sampleCount = 0; 156 unsigned int multiSampleMask = 0; 157 float minSampleShading = 0.0f; 158 159 void set(const VkPipelineMultisampleStateCreateInfo *multisampleState); 160 }; 161 162 struct BlendState : sw::Memset<BlendState> 163 { BlendStatevk::BlendState164 BlendState() 165 : Memset(this, 0) 166 {} 167 BlendStatevk::BlendState168 BlendState(bool alphaBlendEnable, 169 VkBlendFactor sourceBlendFactor, 170 VkBlendFactor destBlendFactor, 171 VkBlendOp blendOperation, 172 VkBlendFactor sourceBlendFactorAlpha, 173 VkBlendFactor destBlendFactorAlpha, 174 VkBlendOp blendOperationAlpha) 175 : Memset(this, 0) 176 , alphaBlendEnable(alphaBlendEnable) 177 , sourceBlendFactor(sourceBlendFactor) 178 , destBlendFactor(destBlendFactor) 179 , blendOperation(blendOperation) 180 , sourceBlendFactorAlpha(sourceBlendFactorAlpha) 181 , destBlendFactorAlpha(destBlendFactorAlpha) 182 , blendOperationAlpha(blendOperationAlpha) 183 {} 184 185 bool alphaBlendEnable; 186 VkBlendFactor sourceBlendFactor; 187 VkBlendFactor destBlendFactor; 188 VkBlendOp blendOperation; 189 VkBlendFactor sourceBlendFactorAlpha; 190 VkBlendFactor destBlendFactorAlpha; 191 VkBlendOp blendOperationAlpha; 192 }; 193 194 struct DynamicVertexInputBindingState 195 { 196 VkVertexInputRate inputRate = VK_VERTEX_INPUT_RATE_VERTEX; 197 VkDeviceSize stride = 0; 198 unsigned int divisor = 0; 199 }; 200 201 struct DynamicVertexInputAttributeState 202 { 203 VkFormat format = VK_FORMAT_UNDEFINED; 204 unsigned int offset = 0; 205 unsigned int binding = 0; 206 }; 207 208 struct DynamicState 209 { 210 VkViewport viewport = {}; 211 VkRect2D scissor = {}; 212 sw::float4 blendConstants = {}; 213 float depthBiasConstantFactor = 0.0f; 214 float depthBiasClamp = 0.0f; 215 float depthBiasSlopeFactor = 0.0f; 216 float minDepthBounds = 0.0f; 217 float maxDepthBounds = 0.0f; 218 float lineWidth = 0.0f; 219 220 VkCullModeFlags cullMode = VK_CULL_MODE_NONE; 221 VkBool32 depthBoundsTestEnable = VK_FALSE; 222 VkCompareOp depthCompareOp = VK_COMPARE_OP_NEVER; 223 VkBool32 depthTestEnable = VK_FALSE; 224 VkBool32 depthWriteEnable = VK_FALSE; 225 VkFrontFace frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; 226 VkPrimitiveTopology primitiveTopology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; 227 uint32_t scissorCount = 0; 228 VkRect2D scissors[vk::MAX_VIEWPORTS] = {}; 229 VkStencilFaceFlags faceMask = (VkStencilFaceFlags)0; 230 VkStencilOpState frontStencil = {}; 231 VkStencilOpState backStencil = {}; 232 VkBool32 stencilTestEnable = VK_FALSE; 233 uint32_t viewportCount = 0; 234 VkRect2D viewports[vk::MAX_VIEWPORTS] = {}; 235 VkBool32 rasterizerDiscardEnable = VK_FALSE; 236 VkBool32 depthBiasEnable = VK_FALSE; 237 VkBool32 primitiveRestartEnable = VK_FALSE; 238 DynamicVertexInputBindingState vertexInputBindings[MAX_VERTEX_INPUT_BINDINGS]; 239 DynamicVertexInputAttributeState vertexInputAttributes[sw::MAX_INTERFACE_COMPONENTS / 4]; 240 }; 241 242 struct VertexInputInterfaceState 243 { 244 void initialize(const VkPipelineVertexInputStateCreateInfo *vertexInputState, 245 const VkPipelineInputAssemblyStateCreateInfo *inputAssemblyState, 246 const DynamicStateFlags &allDynamicStateFlags); 247 248 void applyState(const DynamicState &dynamicState); 249 getTopologyvk::VertexInputInterfaceState250 inline VkPrimitiveTopology getTopology() const { return topology; } hasPrimitiveRestartEnablevk::VertexInputInterfaceState251 inline bool hasPrimitiveRestartEnable() const { return primitiveRestartEnable; } 252 hasDynamicTopologyvk::VertexInputInterfaceState253 inline bool hasDynamicTopology() const { return dynamicStateFlags.dynamicPrimitiveTopology; } hasDynamicPrimitiveRestartEnablevk::VertexInputInterfaceState254 inline bool hasDynamicPrimitiveRestartEnable() const { return dynamicStateFlags.dynamicPrimitiveRestartEnable; } 255 256 bool isDrawPoint(bool polygonModeAware, VkPolygonMode polygonMode) const; 257 bool isDrawLine(bool polygonModeAware, VkPolygonMode polygonMode) const; 258 bool isDrawTriangle(bool polygonModeAware, VkPolygonMode polygonMode) const; 259 260 private: 261 VertexInputInterfaceDynamicStateFlags dynamicStateFlags = {}; 262 263 bool primitiveRestartEnable = false; 264 265 VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; 266 }; 267 268 struct PreRasterizationState 269 { 270 void initialize(const vk::Device *device, 271 const PipelineLayout *layout, 272 const VkPipelineViewportStateCreateInfo *viewportState, 273 const VkPipelineRasterizationStateCreateInfo *rasterizationState, 274 const vk::RenderPass *renderPass, uint32_t subpassIndex, 275 const VkPipelineRenderingCreateInfo *rendering, 276 const DynamicStateFlags &allDynamicStateFlags); 277 getPipelineLayoutvk::PreRasterizationState278 inline const PipelineLayout *getPipelineLayout() const { return pipelineLayout; } overridePipelineLayoutvk::PreRasterizationState279 inline void overridePipelineLayout(const PipelineLayout *linkedLayout) { pipelineLayout = linkedLayout; } 280 281 void applyState(const DynamicState &dynamicState); 282 getCullModevk::PreRasterizationState283 inline VkCullModeFlags getCullMode() const { return cullMode; } getFrontFacevk::PreRasterizationState284 inline VkFrontFace getFrontFace() const { return frontFace; } getPolygonModevk::PreRasterizationState285 inline VkPolygonMode getPolygonMode() const { return polygonMode; } getProvokingVertexModevk::PreRasterizationState286 inline VkProvokingVertexModeEXT getProvokingVertexMode() const { return provokingVertexMode; } getLineRasterizationModevk::PreRasterizationState287 inline VkLineRasterizationModeEXT getLineRasterizationMode() const { return lineRasterizationMode; } 288 hasRasterizerDiscardvk::PreRasterizationState289 inline bool hasRasterizerDiscard() const { return rasterizerDiscard; } 290 getConstantDepthBiasvk::PreRasterizationState291 inline float getConstantDepthBias() const { return depthBiasEnable ? constantDepthBias : 0; } getSlopeDepthBiasvk::PreRasterizationState292 inline float getSlopeDepthBias() const { return depthBiasEnable ? slopeDepthBias : 0; } getDepthBiasClampvk::PreRasterizationState293 inline float getDepthBiasClamp() const { return depthBiasEnable ? depthBiasClamp : 0; } 294 hasDepthRangeUnrestrictedvk::PreRasterizationState295 inline bool hasDepthRangeUnrestricted() const { return depthRangeUnrestricted; } getDepthClampEnablevk::PreRasterizationState296 inline bool getDepthClampEnable() const { return depthClampEnable; } getDepthClipEnablevk::PreRasterizationState297 inline bool getDepthClipEnable() const { return depthClipEnable; } getDepthClipNegativeOneToOnevk::PreRasterizationState298 inline bool getDepthClipNegativeOneToOne() const { return depthClipNegativeOneToOne; } 299 getLineWidthvk::PreRasterizationState300 inline float getLineWidth() const { return lineWidth; } 301 getScissorvk::PreRasterizationState302 inline const VkRect2D &getScissor() const { return scissor; } getViewportvk::PreRasterizationState303 inline const VkViewport &getViewport() const { return viewport; } 304 305 private: 306 const PipelineLayout *pipelineLayout = nullptr; 307 308 PreRasterizationDynamicStateFlags dynamicStateFlags = {}; 309 310 bool rasterizerDiscard = false; 311 bool depthClampEnable = false; 312 bool depthClipEnable = false; 313 bool depthClipNegativeOneToOne = false; 314 bool depthBiasEnable = false; 315 bool depthRangeUnrestricted = false; 316 317 VkCullModeFlags cullMode = 0; 318 VkFrontFace frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; 319 VkPolygonMode polygonMode = VK_POLYGON_MODE_FILL; 320 VkProvokingVertexModeEXT provokingVertexMode = VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT; 321 VkLineRasterizationModeEXT lineRasterizationMode = VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT; 322 323 float depthBiasClamp = 0.0f; 324 float constantDepthBias = 0.0f; 325 float slopeDepthBias = 0.0f; 326 327 float lineWidth = 0.0f; 328 329 VkRect2D scissor = {}; 330 VkViewport viewport = {}; 331 }; 332 333 struct FragmentState 334 { 335 void initialize(const PipelineLayout *layout, 336 const VkPipelineDepthStencilStateCreateInfo *depthStencilState, 337 const vk::RenderPass *renderPass, uint32_t subpassIndex, 338 const VkPipelineRenderingCreateInfo *rendering, 339 const DynamicStateFlags &allDynamicStateFlags); 340 getPipelineLayoutvk::FragmentState341 inline const PipelineLayout *getPipelineLayout() const { return pipelineLayout; } overridePipelineLayoutvk::FragmentState342 inline void overridePipelineLayout(const PipelineLayout *linkedLayout) { pipelineLayout = linkedLayout; } 343 344 void applyState(const DynamicState &dynamicState); 345 getFrontStencilvk::FragmentState346 inline VkStencilOpState getFrontStencil() const { return frontStencil; } getBackStencilvk::FragmentState347 inline VkStencilOpState getBackStencil() const { return backStencil; } 348 getMinDepthBoundsvk::FragmentState349 inline float getMinDepthBounds() const { return minDepthBounds; } getMaxDepthBoundsvk::FragmentState350 inline float getMaxDepthBounds() const { return maxDepthBounds; } 351 getDepthCompareModevk::FragmentState352 inline VkCompareOp getDepthCompareMode() const { return depthCompareMode; } 353 354 bool depthWriteActive(const Attachments &attachments) const; 355 bool depthTestActive(const Attachments &attachments) const; 356 bool stencilActive(const Attachments &attachments) const; 357 bool depthBoundsTestActive(const Attachments &attachments) const; 358 359 private: 360 void setDepthStencilState(const VkPipelineDepthStencilStateCreateInfo *depthStencilState); 361 362 const PipelineLayout *pipelineLayout = nullptr; 363 364 FragmentDynamicStateFlags dynamicStateFlags = {}; 365 366 bool depthTestEnable = false; 367 bool depthWriteEnable = false; 368 bool depthBoundsTestEnable = false; 369 bool stencilEnable = false; 370 371 float minDepthBounds = 0.0f; 372 float maxDepthBounds = 0.0f; 373 374 VkCompareOp depthCompareMode = VK_COMPARE_OP_NEVER; 375 376 VkStencilOpState frontStencil = {}; 377 VkStencilOpState backStencil = {}; 378 379 // Note: if a pipeline library is created with the fragment state only, and sample shading 380 // is enabled or a render pass is provided, VkPipelineMultisampleStateCreateInfo must be 381 // provided. This must identically match with the one provided for the fragment output 382 // interface library. 383 // 384 // Currently, SwiftShader can always use the copy provided and stored in 385 // FragmentOutputInterfaceState. If a future optimization requires access to this state in 386 // a pipeline library without fragment output interface, a copy of MultisampleState can be 387 // placed here and initialized under the above condition. 388 // 389 // Ref: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap10.html#pipeline-graphics-subsets 390 }; 391 392 struct FragmentOutputInterfaceState 393 { 394 void initialize(const VkPipelineColorBlendStateCreateInfo *colorBlendState, 395 const VkPipelineMultisampleStateCreateInfo *multisampleState, 396 const vk::RenderPass *renderPass, uint32_t subpassIndex, 397 const VkPipelineRenderingCreateInfo *rendering, 398 const DynamicStateFlags &allDynamicStateFlags); 399 400 void applyState(const DynamicState &dynamicState); 401 getMultiSampleMaskvk::FragmentOutputInterfaceState402 inline unsigned int getMultiSampleMask() const { return multisample.multiSampleMask; } getSampleCountvk::FragmentOutputInterfaceState403 inline int getSampleCount() const { return multisample.sampleCount; } hasSampleShadingEnabledvk::FragmentOutputInterfaceState404 inline bool hasSampleShadingEnabled() const { return multisample.sampleShadingEnable; } getMinSampleShadingvk::FragmentOutputInterfaceState405 inline float getMinSampleShading() const { return multisample.minSampleShading; } hasAlphaToCoveragevk::FragmentOutputInterfaceState406 inline bool hasAlphaToCoverage() const { return multisample.alphaToCoverage; } 407 getBlendConstantsvk::FragmentOutputInterfaceState408 inline const sw::float4 &getBlendConstants() const { return blendConstants; } 409 410 BlendState getBlendState(int index, const Attachments &attachments, bool fragmentContainsKill) const; 411 412 int colorWriteActive(int index, const Attachments &attachments) const; 413 414 private: 415 void setColorBlendState(const VkPipelineColorBlendStateCreateInfo *colorBlendState); 416 417 VkBlendFactor blendFactor(VkBlendOp blendOperation, VkBlendFactor blendFactor) const; 418 VkBlendOp blendOperation(VkBlendOp blendOperation, VkBlendFactor sourceBlendFactor, VkBlendFactor destBlendFactor, vk::Format format) const; 419 420 bool alphaBlendActive(int index, const Attachments &attachments, bool fragmentContainsKill) const; 421 bool colorWriteActive(const Attachments &attachments) const; 422 423 int colorWriteMask[sw::MAX_COLOR_BUFFERS] = {}; // RGBA 424 425 FragmentOutputInterfaceDynamicStateFlags dynamicStateFlags = {}; 426 427 sw::float4 blendConstants = {}; 428 BlendState blendState[sw::MAX_COLOR_BUFFERS] = {}; 429 430 MultisampleState multisample; 431 }; 432 433 struct GraphicsState 434 { 435 GraphicsState(const Device *device, const VkGraphicsPipelineCreateInfo *pCreateInfo, const PipelineLayout *layout); 436 437 GraphicsState combineStates(const DynamicState &dynamicState) const; 438 hasVertexInputInterfaceStatevk::GraphicsState439 bool hasVertexInputInterfaceState() const 440 { 441 return (validSubset & VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT) != 0; 442 } hasPreRasterizationStatevk::GraphicsState443 bool hasPreRasterizationState() const 444 { 445 return (validSubset & VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT) != 0; 446 } hasFragmentStatevk::GraphicsState447 bool hasFragmentState() const 448 { 449 return (validSubset & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT) != 0; 450 } hasFragmentOutputInterfaceStatevk::GraphicsState451 bool hasFragmentOutputInterfaceState() const 452 { 453 return (validSubset & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT) != 0; 454 } 455 getVertexInputInterfaceStatevk::GraphicsState456 const VertexInputInterfaceState &getVertexInputInterfaceState() const 457 { 458 ASSERT(hasVertexInputInterfaceState()); 459 return vertexInputInterfaceState; 460 } getPreRasterizationStatevk::GraphicsState461 const PreRasterizationState &getPreRasterizationState() const 462 { 463 ASSERT(hasPreRasterizationState()); 464 return preRasterizationState; 465 } getFragmentStatevk::GraphicsState466 const FragmentState &getFragmentState() const 467 { 468 ASSERT(hasFragmentState()); 469 return fragmentState; 470 } getFragmentOutputInterfaceStatevk::GraphicsState471 const FragmentOutputInterfaceState &getFragmentOutputInterfaceState() const 472 { 473 ASSERT(hasFragmentOutputInterfaceState()); 474 return fragmentOutputInterfaceState; 475 } 476 477 private: 478 // The four subsets of a graphics pipeline as described in the spec. With 479 // VK_EXT_graphics_pipeline_library, a number of these may be valid. 480 VertexInputInterfaceState vertexInputInterfaceState; 481 PreRasterizationState preRasterizationState; 482 FragmentState fragmentState; 483 FragmentOutputInterfaceState fragmentOutputInterfaceState; 484 485 VkGraphicsPipelineLibraryFlagsEXT validSubset = 0; 486 }; 487 488 } // namespace vk 489 490 #endif // vk_Context_hpp 491