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 ¤tAttrib = mVertexAttributes[attribIndex];
189 if (memcmp(¤tAttrib, &newAttrib, sizeof(PackedVertexAttribute)) == 0)
190 {
191 return false;
192 }
193
194 memcpy(¤tAttrib, &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