• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
setBlendEnabled(size_t colorIndex,bool enabled)100 bool RenderPipelineDesc::setBlendEnabled(size_t colorIndex, bool enabled)
101 {
102     PackedColorTargetState &colorTarget = mColorTargetStates[colorIndex];
103     if (colorTarget.blendEnabled == enabled)
104     {
105         return false;
106     }
107 
108     SetBitField(colorTarget.blendEnabled, enabled);
109     return true;
110 }
111 
setBlendFuncs(size_t colorIndex,wgpu::BlendFactor srcRGB,wgpu::BlendFactor dstRGB,wgpu::BlendFactor srcAlpha,wgpu::BlendFactor dstAlpha)112 bool RenderPipelineDesc::setBlendFuncs(size_t colorIndex,
113                                        wgpu::BlendFactor srcRGB,
114                                        wgpu::BlendFactor dstRGB,
115                                        wgpu::BlendFactor srcAlpha,
116                                        wgpu::BlendFactor dstAlpha)
117 {
118     bool changed                        = false;
119     PackedColorTargetState &colorTarget = mColorTargetStates[colorIndex];
120 
121     if (colorTarget.colorBlendSrcFactor != static_cast<uint32_t>(srcRGB))
122     {
123         SetBitField(colorTarget.colorBlendSrcFactor, srcRGB);
124         changed = true;
125     }
126 
127     if (colorTarget.colorBlendDstFactor != static_cast<uint32_t>(dstRGB))
128     {
129         SetBitField(colorTarget.colorBlendDstFactor, dstRGB);
130         changed = true;
131     }
132 
133     if (colorTarget.alphaBlendSrcFactor != static_cast<uint32_t>(srcAlpha))
134     {
135         SetBitField(colorTarget.alphaBlendSrcFactor, srcAlpha);
136         changed = true;
137     }
138 
139     if (colorTarget.alphaBlendDstFactor != static_cast<uint32_t>(dstAlpha))
140     {
141         SetBitField(colorTarget.alphaBlendDstFactor, dstAlpha);
142         changed = true;
143     }
144 
145     return changed;
146 }
147 
setBlendEquations(size_t colorIndex,wgpu::BlendOperation rgb,wgpu::BlendOperation alpha)148 bool RenderPipelineDesc::setBlendEquations(size_t colorIndex,
149                                            wgpu::BlendOperation rgb,
150                                            wgpu::BlendOperation alpha)
151 {
152     bool changed                        = false;
153     PackedColorTargetState &colorTarget = mColorTargetStates[colorIndex];
154 
155     if (colorTarget.colorBlendOp != static_cast<uint32_t>(rgb))
156     {
157         SetBitField(colorTarget.colorBlendOp, rgb);
158         changed = true;
159     }
160 
161     if (colorTarget.alphaBlendOp != static_cast<uint32_t>(alpha))
162     {
163         SetBitField(colorTarget.alphaBlendOp, alpha);
164         changed = true;
165     }
166 
167     return changed;
168 }
169 
setFrontFace(GLenum frontFace)170 void RenderPipelineDesc::setFrontFace(GLenum frontFace)
171 {
172     SetBitField(mPrimitiveState.frontFace, PackFrontFace(gl_wgpu::GetFrontFace(frontFace)));
173 }
174 
setCullMode(gl::CullFaceMode cullMode,bool cullFaceEnabled)175 void RenderPipelineDesc::setCullMode(gl::CullFaceMode cullMode, bool cullFaceEnabled)
176 {
177     SetBitField(mPrimitiveState.cullMode, gl_wgpu::GetCullMode(cullMode, cullFaceEnabled));
178 }
179 
setColorWriteMask(size_t colorIndex,bool r,bool g,bool b,bool a)180 void RenderPipelineDesc::setColorWriteMask(size_t colorIndex, bool r, bool g, bool b, bool a)
181 {
182     PackedColorTargetState &colorTarget = mColorTargetStates[colorIndex];
183     SetBitField(colorTarget.writeMask, gl_wgpu::GetColorWriteMask(r, g, b, a));
184 }
185 
setVertexAttribute(size_t attribIndex,PackedVertexAttribute & newAttrib)186 bool RenderPipelineDesc::setVertexAttribute(size_t attribIndex, PackedVertexAttribute &newAttrib)
187 {
188     PackedVertexAttribute &currentAttrib = mVertexAttributes[attribIndex];
189     if (memcmp(&currentAttrib, &newAttrib, sizeof(PackedVertexAttribute)) == 0)
190     {
191         return false;
192     }
193 
194     memcpy(&currentAttrib, &newAttrib, sizeof(PackedVertexAttribute));
195     return true;
196 }
197 
setColorAttachmentFormat(size_t colorIndex,wgpu::TextureFormat format)198 bool RenderPipelineDesc::setColorAttachmentFormat(size_t colorIndex, wgpu::TextureFormat format)
199 {
200     if (mColorTargetStates[colorIndex].format == static_cast<uint8_t>(format))
201     {
202         return false;
203     }
204 
205     SetBitField(mColorTargetStates[colorIndex].format, format);
206     return true;
207 }
208 
setDepthStencilAttachmentFormat(wgpu::TextureFormat format)209 bool RenderPipelineDesc::setDepthStencilAttachmentFormat(wgpu::TextureFormat format)
210 {
211     if (mDepthStencilState.format == static_cast<uint8_t>(format))
212     {
213         return false;
214     }
215 
216     SetBitField(mDepthStencilState.format, format);
217     return true;
218 }
219 
setDepthFunc(wgpu::CompareFunction compareFunc)220 bool RenderPipelineDesc::setDepthFunc(wgpu::CompareFunction compareFunc)
221 {
222     if (mDepthStencilState.depthCompare == static_cast<uint8_t>(compareFunc))
223     {
224         return false;
225     }
226     SetBitField(mDepthStencilState.depthCompare, compareFunc);
227     return true;
228 }
229 
setStencilFrontFunc(wgpu::CompareFunction compareFunc)230 bool RenderPipelineDesc::setStencilFrontFunc(wgpu::CompareFunction compareFunc)
231 {
232     if (mDepthStencilState.stencilFrontCompare == static_cast<uint8_t>(compareFunc))
233     {
234         return false;
235     }
236     SetBitField(mDepthStencilState.stencilFrontCompare, compareFunc);
237     return true;
238 }
239 
setStencilFrontOps(wgpu::StencilOperation failOp,wgpu::StencilOperation depthFailOp,wgpu::StencilOperation passOp)240 bool RenderPipelineDesc::setStencilFrontOps(wgpu::StencilOperation failOp,
241                                             wgpu::StencilOperation depthFailOp,
242                                             wgpu::StencilOperation passOp)
243 {
244     if (mDepthStencilState.stencilFrontFailOp == static_cast<uint8_t>(failOp) &&
245         mDepthStencilState.stencilFrontDepthFailOp == static_cast<uint8_t>(depthFailOp) &&
246         mDepthStencilState.stencilFrontPassOp == static_cast<uint8_t>(passOp))
247     {
248         return false;
249     }
250     SetBitField(mDepthStencilState.stencilFrontFailOp, failOp);
251     SetBitField(mDepthStencilState.stencilFrontDepthFailOp, depthFailOp);
252     SetBitField(mDepthStencilState.stencilFrontPassOp, passOp);
253     return true;
254 }
255 
setStencilBackFunc(wgpu::CompareFunction compareFunc)256 bool RenderPipelineDesc::setStencilBackFunc(wgpu::CompareFunction compareFunc)
257 {
258     if (mDepthStencilState.stencilBackCompare == static_cast<uint8_t>(compareFunc))
259     {
260         return false;
261     }
262     SetBitField(mDepthStencilState.stencilBackCompare, compareFunc);
263     return true;
264 }
265 
setStencilBackOps(wgpu::StencilOperation failOp,wgpu::StencilOperation depthFailOp,wgpu::StencilOperation passOp)266 bool RenderPipelineDesc::setStencilBackOps(wgpu::StencilOperation failOp,
267                                            wgpu::StencilOperation depthFailOp,
268                                            wgpu::StencilOperation passOp)
269 {
270     if (mDepthStencilState.stencilBackFailOp == static_cast<uint8_t>(failOp) &&
271         mDepthStencilState.stencilBackDepthFailOp == static_cast<uint8_t>(depthFailOp) &&
272         mDepthStencilState.stencilBackPassOp == static_cast<uint8_t>(passOp))
273     {
274         return false;
275     }
276     SetBitField(mDepthStencilState.stencilBackFailOp, failOp);
277     SetBitField(mDepthStencilState.stencilBackDepthFailOp, depthFailOp);
278     SetBitField(mDepthStencilState.stencilBackPassOp, passOp);
279     return true;
280 }
281 
setStencilReadMask(uint8_t readMask)282 bool RenderPipelineDesc::setStencilReadMask(uint8_t readMask)
283 {
284 
285     if (mDepthStencilState.stencilReadMask == readMask)
286     {
287         return false;
288     }
289     mDepthStencilState.stencilReadMask = readMask;
290     return true;
291 }
292 
setStencilWriteMask(uint8_t writeMask)293 bool RenderPipelineDesc::setStencilWriteMask(uint8_t writeMask)
294 {
295     if (mDepthStencilState.stencilWriteMask == writeMask)
296     {
297         return false;
298     }
299     mDepthStencilState.stencilWriteMask = writeMask;
300     return true;
301 }
302 
hash() const303 size_t RenderPipelineDesc::hash() const
304 {
305     return angle::ComputeGenericHash(this, sizeof(*this));
306 }
307 
createPipeline(ContextWgpu * context,const wgpu::PipelineLayout & pipelineLayout,const gl::ShaderMap<wgpu::ShaderModule> & shaders,wgpu::RenderPipeline * pipelineOut) const308 angle::Result RenderPipelineDesc::createPipeline(ContextWgpu *context,
309                                                  const wgpu::PipelineLayout &pipelineLayout,
310                                                  const gl::ShaderMap<wgpu::ShaderModule> &shaders,
311                                                  wgpu::RenderPipeline *pipelineOut) const
312 {
313     wgpu::RenderPipelineDescriptor pipelineDesc;
314     pipelineDesc.layout = pipelineLayout;
315 
316     pipelineDesc.vertex.module        = shaders[gl::ShaderType::Vertex];
317     pipelineDesc.vertex.entryPoint    = "wgslMain";
318     pipelineDesc.vertex.constantCount = 0;
319     pipelineDesc.vertex.constants     = nullptr;
320     pipelineDesc.vertex.bufferCount   = 0;
321     pipelineDesc.vertex.buffers       = nullptr;
322 
323     pipelineDesc.primitive.topology =
324         static_cast<wgpu::PrimitiveTopology>(mPrimitiveState.topology);
325     if (webgpu::IsStripPrimitiveTopology(pipelineDesc.primitive.topology))
326     {
327         pipelineDesc.primitive.stripIndexFormat =
328             UnpackIndexFormat(mPrimitiveState.stripIndexFormat);
329     }
330     else
331     {
332         pipelineDesc.primitive.stripIndexFormat = wgpu::IndexFormat::Undefined;
333     }
334     pipelineDesc.primitive.frontFace = UnpackFrontFace(mPrimitiveState.frontFace);
335     pipelineDesc.primitive.cullMode  = static_cast<wgpu::CullMode>(mPrimitiveState.cullMode);
336 
337     size_t attribCount = 0;
338     gl::AttribArray<wgpu::VertexBufferLayout> vertexBuffers;
339     gl::AttribArray<wgpu::VertexAttribute> vertexAttribs;
340 
341     for (PackedVertexAttribute packedAttrib : mVertexAttributes)
342     {
343         if (!packedAttrib.enabled)
344         {
345             continue;
346         }
347 
348         wgpu::VertexAttribute &newAttribute = vertexAttribs[attribCount];
349         newAttribute.format                 = static_cast<wgpu::VertexFormat>(packedAttrib.format);
350         newAttribute.offset                 = packedAttrib.offset;
351         newAttribute.shaderLocation         = packedAttrib.shaderLocation;
352 
353         wgpu::VertexBufferLayout &newBufferLayout = vertexBuffers[attribCount];
354         newBufferLayout.arrayStride               = packedAttrib.stride;
355         newBufferLayout.stepMode                  = wgpu::VertexStepMode::Undefined;
356         newBufferLayout.attributeCount            = 1;
357         newBufferLayout.attributes                = &newAttribute;
358 
359         attribCount++;
360     }
361 
362     pipelineDesc.vertex.bufferCount = attribCount;
363     pipelineDesc.vertex.buffers     = vertexBuffers.data();
364 
365     wgpu::FragmentState fragmentState;
366     std::array<wgpu::ColorTargetState, gl::IMPLEMENTATION_MAX_DRAW_BUFFERS> colorTargets;
367     std::array<wgpu::BlendState, gl::IMPLEMENTATION_MAX_DRAW_BUFFERS> blendStates;
368     if (shaders[gl::ShaderType::Fragment])
369     {
370         fragmentState.module        = shaders[gl::ShaderType::Fragment];
371         fragmentState.entryPoint    = "wgslMain";
372         fragmentState.constantCount = 0;
373         fragmentState.constants     = nullptr;
374 
375         size_t colorTargetCount = 0;
376         for (size_t colorTargetIndex = 0; colorTargetIndex < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
377              ++colorTargetIndex)
378         {
379             const webgpu::PackedColorTargetState &packedColorTarget =
380                 mColorTargetStates[colorTargetIndex];
381             wgpu::ColorTargetState &outputColorTarget = colorTargets[colorTargetIndex];
382 
383             outputColorTarget.format = static_cast<wgpu::TextureFormat>(packedColorTarget.format);
384             if (packedColorTarget.blendEnabled)
385             {
386                 blendStates[colorTargetIndex].color.srcFactor =
387                     static_cast<wgpu::BlendFactor>(packedColorTarget.colorBlendSrcFactor);
388                 blendStates[colorTargetIndex].color.dstFactor =
389                     static_cast<wgpu::BlendFactor>(packedColorTarget.colorBlendDstFactor);
390                 blendStates[colorTargetIndex].color.operation =
391                     static_cast<wgpu::BlendOperation>(packedColorTarget.colorBlendOp);
392 
393                 blendStates[colorTargetIndex].alpha.srcFactor =
394                     static_cast<wgpu::BlendFactor>(packedColorTarget.alphaBlendSrcFactor);
395                 blendStates[colorTargetIndex].alpha.dstFactor =
396                     static_cast<wgpu::BlendFactor>(packedColorTarget.alphaBlendDstFactor);
397                 blendStates[colorTargetIndex].alpha.operation =
398                     static_cast<wgpu::BlendOperation>(packedColorTarget.alphaBlendOp);
399 
400                 outputColorTarget.blend = &blendStates[colorTargetIndex];
401             }
402 
403             outputColorTarget.writeMask =
404                 static_cast<wgpu::ColorWriteMask>(packedColorTarget.writeMask);
405 
406             if (outputColorTarget.format != wgpu::TextureFormat::Undefined)
407             {
408                 colorTargetCount = colorTargetIndex + 1;
409             }
410         }
411         fragmentState.targetCount = colorTargetCount;
412         fragmentState.targets     = colorTargets.data();
413 
414         pipelineDesc.fragment = &fragmentState;
415     }
416 
417     wgpu::DepthStencilState depthStencilState;
418     if (static_cast<wgpu::TextureFormat>(mDepthStencilState.format) !=
419         wgpu::TextureFormat::Undefined)
420     {
421         const webgpu::PackedDepthStencilState &packedDepthStencilState = mDepthStencilState;
422 
423         depthStencilState.format = static_cast<wgpu::TextureFormat>(packedDepthStencilState.format);
424         depthStencilState.depthWriteEnabled =
425             static_cast<bool>(packedDepthStencilState.depthWriteEnabled);
426         depthStencilState.depthCompare =
427             static_cast<wgpu::CompareFunction>(packedDepthStencilState.depthCompare);
428 
429         depthStencilState.stencilFront.compare =
430             static_cast<wgpu::CompareFunction>(packedDepthStencilState.stencilFrontCompare);
431         depthStencilState.stencilFront.failOp =
432             static_cast<wgpu::StencilOperation>(packedDepthStencilState.stencilFrontFailOp);
433         depthStencilState.stencilFront.depthFailOp =
434             static_cast<wgpu::StencilOperation>(packedDepthStencilState.stencilFrontDepthFailOp);
435         depthStencilState.stencilFront.passOp =
436             static_cast<wgpu::StencilOperation>(packedDepthStencilState.stencilFrontPassOp);
437 
438         depthStencilState.stencilBack.compare =
439             static_cast<wgpu::CompareFunction>(packedDepthStencilState.stencilBackCompare);
440         depthStencilState.stencilBack.failOp =
441             static_cast<wgpu::StencilOperation>(packedDepthStencilState.stencilBackFailOp);
442         depthStencilState.stencilBack.depthFailOp =
443             static_cast<wgpu::StencilOperation>(packedDepthStencilState.stencilBackDepthFailOp);
444         depthStencilState.stencilBack.passOp =
445             static_cast<wgpu::StencilOperation>(packedDepthStencilState.stencilBackPassOp);
446 
447         depthStencilState.stencilReadMask  = packedDepthStencilState.stencilReadMask;
448         depthStencilState.stencilWriteMask = packedDepthStencilState.stencilWriteMask;
449 
450         depthStencilState.depthBias           = packedDepthStencilState.depthBias;
451         depthStencilState.depthBiasSlopeScale = packedDepthStencilState.depthBiasSlopeScalef;
452         depthStencilState.depthBiasClamp      = packedDepthStencilState.depthBiasClamp;
453 
454         pipelineDesc.depthStencil = &depthStencilState;
455     }
456 
457     wgpu::Device device = context->getDevice();
458     ANGLE_WGPU_SCOPED_DEBUG_TRY(context, *pipelineOut = device.CreateRenderPipeline(&pipelineDesc));
459 
460     return angle::Result::Continue;
461 }
462 
operator ==(const RenderPipelineDesc & lhs,const RenderPipelineDesc & rhs)463 bool operator==(const RenderPipelineDesc &lhs, const RenderPipelineDesc &rhs)
464 {
465     return memcmp(&lhs, &rhs, sizeof(RenderPipelineDesc)) == 0;
466 }
467 
468 // PipelineCache implementation.
469 PipelineCache::PipelineCache()  = default;
470 PipelineCache::~PipelineCache() = default;
471 
getRenderPipeline(ContextWgpu * context,const RenderPipelineDesc & desc,const wgpu::PipelineLayout & pipelineLayout,const gl::ShaderMap<wgpu::ShaderModule> & shaders,wgpu::RenderPipeline * pipelineOut)472 angle::Result PipelineCache::getRenderPipeline(ContextWgpu *context,
473                                                const RenderPipelineDesc &desc,
474                                                const wgpu::PipelineLayout &pipelineLayout,
475                                                const gl::ShaderMap<wgpu::ShaderModule> &shaders,
476                                                wgpu::RenderPipeline *pipelineOut)
477 {
478     auto iter = mRenderPipelines.find(desc);
479     if (iter != mRenderPipelines.end())
480     {
481         *pipelineOut = iter->second;
482         return angle::Result::Continue;
483     }
484 
485     ANGLE_TRY(desc.createPipeline(context, pipelineLayout, shaders, pipelineOut));
486     mRenderPipelines.insert(std::make_pair(desc, *pipelineOut));
487 
488     return angle::Result::Continue;
489 }
490 
491 }  // namespace webgpu
492 
493 }  // namespace rx
494