// // Copyright 2024 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // #ifndef LIBANGLE_RENDERER_WGPU_PIPELINE_STATE_H_ #define LIBANGLE_RENDERER_WGPU_PIPELINE_STATE_H_ #include #include #include #include "libANGLE/Constants.h" #include "libANGLE/Error.h" #include "libANGLE/angletypes.h" #include "common/PackedEnums.h" namespace rx { class ContextWgpu; namespace webgpu { ANGLE_ENABLE_STRUCT_PADDING_WARNINGS constexpr uint32_t kPrimitiveTopologyBitCount = 3; constexpr uint32_t kIndexFormatBitCount = 1; constexpr uint32_t kFrontFaceBitCount = 1; constexpr uint32_t kCullModeBitCount = 2; struct PackedPrimitiveState final { uint8_t topology : kPrimitiveTopologyBitCount; uint8_t stripIndexFormat : kIndexFormatBitCount; uint8_t frontFace : kFrontFaceBitCount; uint8_t cullMode : kCullModeBitCount; uint8_t pad0 : 1; }; constexpr size_t kPackedPrimitiveStateSize = sizeof(PackedPrimitiveState); static_assert(kPackedPrimitiveStateSize == 1, "Size mismatch"); constexpr uint32_t kTextureFormatBitCount = 19; constexpr uint32_t kColorWriteMaskBitCount = 4; constexpr uint32_t kBlendFactorBitCount = 5; constexpr uint32_t kBlendOperationBitCount = 3; struct PackedColorTargetState final { uint32_t format : kTextureFormatBitCount; uint32_t blendEnabled : 1; uint32_t colorBlendSrcFactor : kBlendFactorBitCount; uint32_t colorBlendDstFactor : kBlendFactorBitCount; uint32_t pad0 : 2; uint32_t colorBlendOp : kBlendOperationBitCount; uint32_t alphaBlendSrcFactor : kBlendFactorBitCount; uint32_t alphaBlendDstFactor : kBlendFactorBitCount; uint32_t alphaBlendOp : kBlendOperationBitCount; uint32_t writeMask : kColorWriteMaskBitCount; uint32_t pad1 : 12; }; constexpr size_t kPackedColorTargetStateSize = sizeof(PackedColorTargetState); static_assert(kPackedColorTargetStateSize == 8, "Size mismatch"); constexpr uint32_t kCompareFunctionBitCount = 4; constexpr uint32_t kStencilOperationBitCount = 4; struct PackedDepthStencilState final { uint32_t format : kTextureFormatBitCount; uint32_t depthWriteEnabled : 1; uint32_t depthCompare : kCompareFunctionBitCount; uint32_t stencilFrontCompare : kCompareFunctionBitCount; uint32_t stencilFrontFailOp : kStencilOperationBitCount; uint32_t stencilFrontDepthFailOp : kStencilOperationBitCount; uint32_t stencilFrontPassOp : kStencilOperationBitCount; uint32_t stencilBackCompare : kCompareFunctionBitCount; uint32_t stencilBackFailOp : kStencilOperationBitCount; uint32_t stencilBackDepthFailOp : kStencilOperationBitCount; uint32_t stencilBackPassOp : kStencilOperationBitCount; uint32_t pad0 : 8; uint8_t stencilReadMask; uint8_t stencilWriteMask; uint8_t pad1[2]; int32_t depthBias; float depthBiasSlopeScalef; float depthBiasClamp; }; constexpr size_t kPackedDepthStencilStateSize = sizeof(PackedDepthStencilState); static_assert(kPackedDepthStencilStateSize == 24, "Size mismatch"); constexpr uint32_t kVertexFormatBitCount = 5; // A maximum offset of 4096 covers almost every Vulkan driver on desktop (80%) and mobile (99%). The // next highest values to meet native drivers are 16 bits or 32 bits. constexpr uint32_t kAttributeOffsetMaxBits = 15; // In WebGPU, the maxVertexBufferArrayStride will be at least 2048. constexpr uint32_t kVertexAttributeStrideBits = 16; struct PackedVertexAttribute final { PackedVertexAttribute(); uint16_t offset : kAttributeOffsetMaxBits; uint16_t enabled : 1; uint8_t format : kVertexFormatBitCount; uint8_t pad1 : 3; uint8_t shaderLocation; uint16_t stride : kVertexAttributeStrideBits; }; constexpr size_t kPackedVertexAttributeSize = sizeof(PackedVertexAttribute); static_assert(kPackedVertexAttributeSize == 6, "Size mismatch"); class RenderPipelineDesc final { public: RenderPipelineDesc(); ~RenderPipelineDesc(); RenderPipelineDesc(const RenderPipelineDesc &other); RenderPipelineDesc &operator=(const RenderPipelineDesc &other); // Returns true if the pipeline description has changed bool setPrimitiveMode(gl::PrimitiveMode primitiveMode, gl::DrawElementsType indexTypeOrInvalid); void setFrontFace(GLenum frontFace); void setCullMode(gl::CullFaceMode cullMode, bool cullFaceEnabled); void setColorWriteMask(size_t colorIndex, bool r, bool g, bool b, bool a); bool setBlendEnabled(size_t colorIndex, bool enabled); bool setBlendFuncs(size_t colorIndex, wgpu::BlendFactor srcRGB, wgpu::BlendFactor dstRGB, wgpu::BlendFactor srcAlpha, wgpu::BlendFactor dstAlpha); bool setBlendEquations(size_t colorIndex, wgpu::BlendOperation rgb, wgpu::BlendOperation alpha); bool setVertexAttribute(size_t attribIndex, PackedVertexAttribute &newAttrib); bool setColorAttachmentFormat(size_t colorIndex, wgpu::TextureFormat format); bool setDepthStencilAttachmentFormat(wgpu::TextureFormat format); bool setDepthFunc(wgpu::CompareFunction compareFunc); bool setStencilFrontFunc(wgpu::CompareFunction compareFunc); bool setStencilFrontOps(wgpu::StencilOperation failOp, wgpu::StencilOperation depthFailOp, wgpu::StencilOperation passOp); bool setStencilBackFunc(wgpu::CompareFunction compareFunc); bool setStencilBackOps(wgpu::StencilOperation failOp, wgpu::StencilOperation depthFailOp, wgpu::StencilOperation passOp); bool setStencilReadMask(uint8_t readeMask); bool setStencilWriteMask(uint8_t writeMask); size_t hash() const; angle::Result createPipeline(ContextWgpu *context, const wgpu::PipelineLayout &pipelineLayout, const gl::ShaderMap &shaders, wgpu::RenderPipeline *pipelineOut) const; private: PackedVertexAttribute mVertexAttributes[gl::MAX_VERTEX_ATTRIBS]; PackedColorTargetState mColorTargetStates[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS]; PackedDepthStencilState mDepthStencilState; PackedPrimitiveState mPrimitiveState; uint8_t mPad0[3]; }; constexpr size_t kRenderPipelineDescSize = sizeof(RenderPipelineDesc); static_assert(kRenderPipelineDescSize % 4 == 0, "RenderPipelineDesc size must be a multiple of 4 bytes."); bool operator==(const RenderPipelineDesc &lhs, const RenderPipelineDesc &rhs); ANGLE_DISABLE_STRUCT_PADDING_WARNINGS } // namespace webgpu } // namespace rx // Introduce std::hash for the above classes. namespace std { template <> struct hash { size_t operator()(const rx::webgpu::RenderPipelineDesc &key) const { return key.hash(); } }; } // namespace std namespace rx { namespace webgpu { class PipelineCache final { public: PipelineCache(); ~PipelineCache(); angle::Result getRenderPipeline(ContextWgpu *context, const RenderPipelineDesc &desc, const wgpu::PipelineLayout &pipelineLayout, const gl::ShaderMap &shaders, wgpu::RenderPipeline *pipelineOut); private: std::unordered_map mRenderPipelines; }; } // namespace webgpu } // namespace rx #endif // LIBANGLE_RENDERER_WGPU_PIPELINE_STATE_H_