xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/wgpu/wgpu_pipeline_state.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2024 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 #include "libANGLE/renderer/wgpu/wgpu_pipeline_state.h"
8 
9 #include "common/aligned_memory.h"
10 #include "common/hash_utils.h"
11 #include "libANGLE/Error.h"
12 #include "libANGLE/renderer/wgpu/ContextWgpu.h"
13 #include "libANGLE/renderer/wgpu/wgpu_utils.h"
14 
15 namespace rx
16 {
17 namespace webgpu
18 {
19 // Can pack the index format into 1 bit since it has 2 values and Undefined is not used.
20 static_assert(static_cast<uint32_t>(wgpu::IndexFormat::Uint32) == 2U,
21               "Max wgpu::IndexFormat is not 2");
22 static_assert(static_cast<uint32_t>(wgpu::IndexFormat::Undefined) == 0,
23               "wgpu::IndexFormat::Undefined unexpected value");
PackIndexFormat(wgpu::IndexFormat unpackedFormat)24 constexpr uint32_t PackIndexFormat(wgpu::IndexFormat unpackedFormat)
25 {
26     ASSERT(static_cast<uint32_t>(unpackedFormat) > 0);
27     return static_cast<uint32_t>(unpackedFormat) - 1;
28 }
29 
UnpackIndexFormat(uint32_t packedIndexFormat)30 constexpr wgpu::IndexFormat UnpackIndexFormat(uint32_t packedIndexFormat)
31 {
32     return static_cast<wgpu::IndexFormat>(packedIndexFormat + 1);
33 }
34 
35 // Can pack the front face into 1 bit since it has 2 values and Undefined is not used.
36 static_assert(static_cast<uint32_t>(wgpu::FrontFace::CW) == 2U, "Max wgpu::FrontFace is not 2");
37 static_assert(static_cast<uint32_t>(wgpu::FrontFace::Undefined) == 0,
38               "wgpu::FrontFace::Undefined unexpected value");
PackFrontFace(wgpu::FrontFace unpackedFrontFace)39 constexpr uint32_t PackFrontFace(wgpu::FrontFace unpackedFrontFace)
40 {
41     ASSERT(static_cast<uint32_t>(unpackedFrontFace) > 0);
42     return static_cast<uint32_t>(unpackedFrontFace) - 1;
43 }
44 
UnpackFrontFace(uint32_t packedFrontFace)45 constexpr wgpu::FrontFace UnpackFrontFace(uint32_t packedFrontFace)
46 {
47     return static_cast<wgpu::FrontFace>(packedFrontFace + 1);
48 }
49 
PackedVertexAttribute()50 PackedVertexAttribute::PackedVertexAttribute()
51 {
52     memset(this, 0, sizeof(PackedVertexAttribute));
53 }
54 
55 // GraphicsPipelineDesc implementation.
RenderPipelineDesc()56 RenderPipelineDesc::RenderPipelineDesc()
57 {
58     (void)mPad0;
59     memset(this, 0, sizeof(RenderPipelineDesc));
60 }
61 
62 RenderPipelineDesc::~RenderPipelineDesc() = default;
63 
RenderPipelineDesc(const RenderPipelineDesc & other)64 RenderPipelineDesc::RenderPipelineDesc(const RenderPipelineDesc &other)
65 {
66     *this = other;
67 }
68 
operator =(const RenderPipelineDesc & other)69 RenderPipelineDesc &RenderPipelineDesc::operator=(const RenderPipelineDesc &other)
70 {
71     memcpy(this, &other, sizeof(*this));
72     return *this;
73 }
74 
setPrimitiveMode(gl::PrimitiveMode primitiveMode,gl::DrawElementsType indexTypeOrInvalid)75 bool RenderPipelineDesc::setPrimitiveMode(gl::PrimitiveMode primitiveMode,
76                                           gl::DrawElementsType indexTypeOrInvalid)
77 {
78     bool changed = false;
79 
80     wgpu::PrimitiveTopology topology = gl_wgpu::GetPrimitiveTopology(primitiveMode);
81     if (mPrimitiveState.topology != static_cast<uint8_t>(topology))
82     {
83         SetBitField(mPrimitiveState.topology, topology);
84         changed = true;
85     }
86 
87     uint32_t indexFormat = webgpu::IsStripPrimitiveTopology(topology) &&
88                                    indexTypeOrInvalid != gl::DrawElementsType::InvalidEnum
89                                ? PackIndexFormat(gl_wgpu::GetIndexFormat(indexTypeOrInvalid))
90                                : 0;
91     if (mPrimitiveState.stripIndexFormat != static_cast<uint8_t>(indexFormat))
92     {
93         SetBitField(mPrimitiveState.stripIndexFormat, indexFormat);
94         changed = true;
95     }
96 
97     return changed;
98 }
99 
setFrontFace(GLenum frontFace)100 void RenderPipelineDesc::setFrontFace(GLenum frontFace)
101 {
102     SetBitField(mPrimitiveState.frontFace, PackFrontFace(gl_wgpu::GetFrontFace(frontFace)));
103 }
104 
setCullMode(gl::CullFaceMode cullMode,bool cullFaceEnabled)105 void RenderPipelineDesc::setCullMode(gl::CullFaceMode cullMode, bool cullFaceEnabled)
106 {
107     SetBitField(mPrimitiveState.cullMode, gl_wgpu::GetCullMode(cullMode, cullFaceEnabled));
108 }
109 
setColorWriteMask(size_t colorIndex,bool r,bool g,bool b,bool a)110 void RenderPipelineDesc::setColorWriteMask(size_t colorIndex, bool r, bool g, bool b, bool a)
111 {
112     PackedColorTargetState &colorTarget = mColorTargetStates[colorIndex];
113     SetBitField(colorTarget.writeMask, gl_wgpu::GetColorWriteMask(r, g, b, a));
114 }
115 
setVertexAttribute(size_t attribIndex,PackedVertexAttribute & newAttrib)116 bool RenderPipelineDesc::setVertexAttribute(size_t attribIndex, PackedVertexAttribute &newAttrib)
117 {
118     PackedVertexAttribute &currentAttrib = mVertexAttributes[attribIndex];
119     if (memcmp(&currentAttrib, &newAttrib, sizeof(PackedVertexAttribute)) == 0)
120     {
121         return false;
122     }
123 
124     memcpy(&currentAttrib, &newAttrib, sizeof(PackedVertexAttribute));
125     return true;
126 }
127 
setColorAttachmentFormat(size_t colorIndex,wgpu::TextureFormat format)128 bool RenderPipelineDesc::setColorAttachmentFormat(size_t colorIndex, wgpu::TextureFormat format)
129 {
130     if (mColorTargetStates[colorIndex].format == static_cast<uint8_t>(format))
131     {
132         return false;
133     }
134 
135     SetBitField(mColorTargetStates[colorIndex].format, format);
136     return true;
137 }
138 
setDepthStencilAttachmentFormat(wgpu::TextureFormat format)139 bool RenderPipelineDesc::setDepthStencilAttachmentFormat(wgpu::TextureFormat format)
140 {
141     if (mDepthStencilState.format == static_cast<uint8_t>(format))
142     {
143         return false;
144     }
145 
146     SetBitField(mDepthStencilState.format, format);
147     return true;
148 }
149 
setDepthFunc(wgpu::CompareFunction compareFunc)150 bool RenderPipelineDesc::setDepthFunc(wgpu::CompareFunction compareFunc)
151 {
152     if (mDepthStencilState.depthCompare == static_cast<uint8_t>(compareFunc))
153     {
154         return false;
155     }
156     SetBitField(mDepthStencilState.depthCompare, compareFunc);
157     return true;
158 }
159 
setStencilFrontFunc(wgpu::CompareFunction compareFunc)160 bool RenderPipelineDesc::setStencilFrontFunc(wgpu::CompareFunction compareFunc)
161 {
162     if (mDepthStencilState.stencilFrontCompare == static_cast<uint8_t>(compareFunc))
163     {
164         return false;
165     }
166     SetBitField(mDepthStencilState.stencilFrontCompare, compareFunc);
167     return true;
168 }
169 
setStencilFrontOps(wgpu::StencilOperation failOp,wgpu::StencilOperation depthFailOp,wgpu::StencilOperation passOp)170 bool RenderPipelineDesc::setStencilFrontOps(wgpu::StencilOperation failOp,
171                                             wgpu::StencilOperation depthFailOp,
172                                             wgpu::StencilOperation passOp)
173 {
174     if (mDepthStencilState.stencilFrontFailOp == static_cast<uint8_t>(failOp) &&
175         mDepthStencilState.stencilFrontDepthFailOp == static_cast<uint8_t>(depthFailOp) &&
176         mDepthStencilState.stencilFrontPassOp == static_cast<uint8_t>(passOp))
177     {
178         return false;
179     }
180     SetBitField(mDepthStencilState.stencilFrontFailOp, failOp);
181     SetBitField(mDepthStencilState.stencilFrontDepthFailOp, depthFailOp);
182     SetBitField(mDepthStencilState.stencilFrontPassOp, passOp);
183     return true;
184 }
185 
setStencilBackFunc(wgpu::CompareFunction compareFunc)186 bool RenderPipelineDesc::setStencilBackFunc(wgpu::CompareFunction compareFunc)
187 {
188     if (mDepthStencilState.stencilBackCompare == static_cast<uint8_t>(compareFunc))
189     {
190         return false;
191     }
192     SetBitField(mDepthStencilState.stencilBackCompare, compareFunc);
193     return true;
194 }
195 
setStencilBackOps(wgpu::StencilOperation failOp,wgpu::StencilOperation depthFailOp,wgpu::StencilOperation passOp)196 bool RenderPipelineDesc::setStencilBackOps(wgpu::StencilOperation failOp,
197                                            wgpu::StencilOperation depthFailOp,
198                                            wgpu::StencilOperation passOp)
199 {
200     if (mDepthStencilState.stencilBackFailOp == static_cast<uint8_t>(failOp) &&
201         mDepthStencilState.stencilBackDepthFailOp == static_cast<uint8_t>(depthFailOp) &&
202         mDepthStencilState.stencilBackPassOp == static_cast<uint8_t>(passOp))
203     {
204         return false;
205     }
206     SetBitField(mDepthStencilState.stencilBackFailOp, failOp);
207     SetBitField(mDepthStencilState.stencilBackDepthFailOp, depthFailOp);
208     SetBitField(mDepthStencilState.stencilBackPassOp, passOp);
209     return true;
210 }
211 
setStencilReadMask(uint8_t readMask)212 bool RenderPipelineDesc::setStencilReadMask(uint8_t readMask)
213 {
214 
215     if (mDepthStencilState.stencilReadMask == readMask)
216     {
217         return false;
218     }
219     mDepthStencilState.stencilReadMask = readMask;
220     return true;
221 }
222 
setStencilWriteMask(uint8_t writeMask)223 bool RenderPipelineDesc::setStencilWriteMask(uint8_t writeMask)
224 {
225     if (mDepthStencilState.stencilWriteMask == writeMask)
226     {
227         return false;
228     }
229     mDepthStencilState.stencilWriteMask = writeMask;
230     return true;
231 }
232 
hash() const233 size_t RenderPipelineDesc::hash() const
234 {
235     return angle::ComputeGenericHash(this, sizeof(*this));
236 }
237 
createPipeline(ContextWgpu * context,const wgpu::PipelineLayout & pipelineLayout,const gl::ShaderMap<wgpu::ShaderModule> & shaders,wgpu::RenderPipeline * pipelineOut) const238 angle::Result RenderPipelineDesc::createPipeline(ContextWgpu *context,
239                                                  const wgpu::PipelineLayout &pipelineLayout,
240                                                  const gl::ShaderMap<wgpu::ShaderModule> &shaders,
241                                                  wgpu::RenderPipeline *pipelineOut) const
242 {
243     wgpu::RenderPipelineDescriptor pipelineDesc;
244     pipelineDesc.layout = pipelineLayout;
245 
246     pipelineDesc.vertex.module        = shaders[gl::ShaderType::Vertex];
247     pipelineDesc.vertex.entryPoint    = "wgslMain";
248     pipelineDesc.vertex.constantCount = 0;
249     pipelineDesc.vertex.constants     = nullptr;
250     pipelineDesc.vertex.bufferCount   = 0;
251     pipelineDesc.vertex.buffers       = nullptr;
252 
253     pipelineDesc.primitive.topology =
254         static_cast<wgpu::PrimitiveTopology>(mPrimitiveState.topology);
255     if (webgpu::IsStripPrimitiveTopology(pipelineDesc.primitive.topology))
256     {
257         pipelineDesc.primitive.stripIndexFormat =
258             UnpackIndexFormat(mPrimitiveState.stripIndexFormat);
259     }
260     else
261     {
262         pipelineDesc.primitive.stripIndexFormat = wgpu::IndexFormat::Undefined;
263     }
264     pipelineDesc.primitive.frontFace = UnpackFrontFace(mPrimitiveState.frontFace);
265     pipelineDesc.primitive.cullMode  = static_cast<wgpu::CullMode>(mPrimitiveState.cullMode);
266 
267     size_t attribCount = 0;
268     gl::AttribArray<wgpu::VertexBufferLayout> vertexBuffers;
269     gl::AttribArray<wgpu::VertexAttribute> vertexAttribs;
270 
271     for (PackedVertexAttribute packedAttrib : mVertexAttributes)
272     {
273         if (!packedAttrib.enabled)
274         {
275             continue;
276         }
277 
278         wgpu::VertexAttribute &newAttribute = vertexAttribs[attribCount];
279         newAttribute.format                 = static_cast<wgpu::VertexFormat>(packedAttrib.format);
280         newAttribute.offset                 = packedAttrib.offset;
281         newAttribute.shaderLocation         = packedAttrib.shaderLocation;
282 
283         wgpu::VertexBufferLayout &newBufferLayout = vertexBuffers[attribCount];
284         newBufferLayout.arrayStride               = packedAttrib.stride;
285         newBufferLayout.attributeCount            = 1;
286         newBufferLayout.attributes                = &newAttribute;
287 
288         attribCount++;
289     }
290 
291     pipelineDesc.vertex.bufferCount = attribCount;
292     pipelineDesc.vertex.buffers     = vertexBuffers.data();
293 
294     wgpu::FragmentState fragmentState;
295     std::array<wgpu::ColorTargetState, gl::IMPLEMENTATION_MAX_DRAW_BUFFERS> colorTargets;
296     std::array<wgpu::BlendState, gl::IMPLEMENTATION_MAX_DRAW_BUFFERS> blendStates;
297     if (shaders[gl::ShaderType::Fragment])
298     {
299         fragmentState.module        = shaders[gl::ShaderType::Fragment];
300         fragmentState.entryPoint    = "wgslMain";
301         fragmentState.constantCount = 0;
302         fragmentState.constants     = nullptr;
303 
304         size_t colorTargetCount = 0;
305         for (size_t colorTargetIndex = 0; colorTargetIndex < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
306              ++colorTargetIndex)
307         {
308             const webgpu::PackedColorTargetState &packedColorTarget =
309                 mColorTargetStates[colorTargetIndex];
310             wgpu::ColorTargetState &outputColorTarget = colorTargets[colorTargetIndex];
311 
312             outputColorTarget.format = static_cast<wgpu::TextureFormat>(packedColorTarget.format);
313             if (packedColorTarget.blendEnabled)
314             {
315                 blendStates[colorTargetIndex].color.srcFactor =
316                     static_cast<wgpu::BlendFactor>(packedColorTarget.colorBlendSrcFactor);
317                 blendStates[colorTargetIndex].color.dstFactor =
318                     static_cast<wgpu::BlendFactor>(packedColorTarget.colorBlendDstFactor);
319                 blendStates[colorTargetIndex].color.operation =
320                     static_cast<wgpu::BlendOperation>(packedColorTarget.colorBlendOp);
321 
322                 blendStates[colorTargetIndex].alpha.srcFactor =
323                     static_cast<wgpu::BlendFactor>(packedColorTarget.alphaBlendSrcFactor);
324                 blendStates[colorTargetIndex].alpha.dstFactor =
325                     static_cast<wgpu::BlendFactor>(packedColorTarget.alphaBlendDstFactor);
326                 blendStates[colorTargetIndex].alpha.operation =
327                     static_cast<wgpu::BlendOperation>(packedColorTarget.alphaBlendOp);
328             }
329 
330             outputColorTarget.writeMask =
331                 static_cast<wgpu::ColorWriteMask>(packedColorTarget.writeMask);
332 
333             if (outputColorTarget.format != wgpu::TextureFormat::Undefined)
334             {
335                 colorTargetCount = colorTargetIndex + 1;
336             }
337         }
338         fragmentState.targetCount = colorTargetCount;
339         fragmentState.targets     = colorTargets.data();
340 
341         pipelineDesc.fragment = &fragmentState;
342     }
343 
344     wgpu::DepthStencilState depthStencilState;
345     if (static_cast<wgpu::TextureFormat>(mDepthStencilState.format) !=
346         wgpu::TextureFormat::Undefined)
347     {
348         const webgpu::PackedDepthStencilState &packedDepthStencilState = mDepthStencilState;
349 
350         depthStencilState.format = static_cast<wgpu::TextureFormat>(packedDepthStencilState.format);
351         depthStencilState.depthWriteEnabled =
352             static_cast<bool>(packedDepthStencilState.depthWriteEnabled);
353         depthStencilState.depthCompare =
354             static_cast<wgpu::CompareFunction>(packedDepthStencilState.depthCompare);
355 
356         depthStencilState.stencilFront.compare =
357             static_cast<wgpu::CompareFunction>(packedDepthStencilState.stencilFrontCompare);
358         depthStencilState.stencilFront.failOp =
359             static_cast<wgpu::StencilOperation>(packedDepthStencilState.stencilFrontFailOp);
360         depthStencilState.stencilFront.depthFailOp =
361             static_cast<wgpu::StencilOperation>(packedDepthStencilState.stencilFrontDepthFailOp);
362         depthStencilState.stencilFront.passOp =
363             static_cast<wgpu::StencilOperation>(packedDepthStencilState.stencilFrontPassOp);
364 
365         depthStencilState.stencilBack.compare =
366             static_cast<wgpu::CompareFunction>(packedDepthStencilState.stencilBackCompare);
367         depthStencilState.stencilBack.failOp =
368             static_cast<wgpu::StencilOperation>(packedDepthStencilState.stencilBackFailOp);
369         depthStencilState.stencilBack.depthFailOp =
370             static_cast<wgpu::StencilOperation>(packedDepthStencilState.stencilBackDepthFailOp);
371         depthStencilState.stencilBack.passOp =
372             static_cast<wgpu::StencilOperation>(packedDepthStencilState.stencilBackPassOp);
373 
374         depthStencilState.stencilReadMask  = packedDepthStencilState.stencilReadMask;
375         depthStencilState.stencilWriteMask = packedDepthStencilState.stencilWriteMask;
376 
377         depthStencilState.depthBias           = packedDepthStencilState.depthBias;
378         depthStencilState.depthBiasSlopeScale = packedDepthStencilState.depthBiasSlopeScalef;
379         depthStencilState.depthBiasClamp      = packedDepthStencilState.depthBiasClamp;
380 
381         pipelineDesc.depthStencil = &depthStencilState;
382     }
383 
384     wgpu::Device device = context->getDevice();
385     ANGLE_WGPU_SCOPED_DEBUG_TRY(context, *pipelineOut = device.CreateRenderPipeline(&pipelineDesc));
386 
387     return angle::Result::Continue;
388 }
389 
operator ==(const RenderPipelineDesc & lhs,const RenderPipelineDesc & rhs)390 bool operator==(const RenderPipelineDesc &lhs, const RenderPipelineDesc &rhs)
391 {
392     return memcmp(&lhs, &rhs, sizeof(RenderPipelineDesc)) == 0;
393 }
394 
395 // PipelineCache implementation.
396 PipelineCache::PipelineCache()  = default;
397 PipelineCache::~PipelineCache() = default;
398 
getRenderPipeline(ContextWgpu * context,const RenderPipelineDesc & desc,const wgpu::PipelineLayout & pipelineLayout,const gl::ShaderMap<wgpu::ShaderModule> & shaders,wgpu::RenderPipeline * pipelineOut)399 angle::Result PipelineCache::getRenderPipeline(ContextWgpu *context,
400                                                const RenderPipelineDesc &desc,
401                                                const wgpu::PipelineLayout &pipelineLayout,
402                                                const gl::ShaderMap<wgpu::ShaderModule> &shaders,
403                                                wgpu::RenderPipeline *pipelineOut)
404 {
405     auto iter = mRenderPipelines.find(desc);
406     if (iter != mRenderPipelines.end())
407     {
408         *pipelineOut = iter->second;
409         return angle::Result::Continue;
410     }
411 
412     ANGLE_TRY(desc.createPipeline(context, pipelineLayout, shaders, pipelineOut));
413     mRenderPipelines.insert(std::make_pair(desc, *pipelineOut));
414 
415     return angle::Result::Continue;
416 }
417 
418 }  // namespace webgpu
419 
420 }  // namespace rx
421