xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/wgpu/wgpu_utils.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_utils.h"
8 
9 #include "libANGLE/renderer/renderer_utils.h"
10 #include "libANGLE/renderer/wgpu/ContextWgpu.h"
11 #include "libANGLE/renderer/wgpu/DisplayWgpu.h"
12 #include "libANGLE/renderer/wgpu/wgpu_pipeline_state.h"
13 
14 namespace rx
15 {
16 
17 namespace webgpu
18 {
GetDisplay(const gl::Context * context)19 DisplayWgpu *GetDisplay(const gl::Context *context)
20 {
21     ContextWgpu *contextWgpu = GetImpl(context);
22     return contextWgpu->getDisplay();
23 }
24 
GetDevice(const gl::Context * context)25 wgpu::Device GetDevice(const gl::Context *context)
26 {
27     DisplayWgpu *display = GetDisplay(context);
28     return display->getDevice();
29 }
30 
GetInstance(const gl::Context * context)31 wgpu::Instance GetInstance(const gl::Context *context)
32 {
33     DisplayWgpu *display = GetDisplay(context);
34     return display->getInstance();
35 }
36 
CreateNewClearColorAttachment(wgpu::Color clearValue,uint32_t depthSlice,wgpu::TextureView textureView)37 wgpu::RenderPassColorAttachment CreateNewClearColorAttachment(wgpu::Color clearValue,
38                                                               uint32_t depthSlice,
39                                                               wgpu::TextureView textureView)
40 {
41     wgpu::RenderPassColorAttachment colorAttachment;
42     colorAttachment.view       = textureView;
43     colorAttachment.depthSlice = depthSlice;
44     colorAttachment.loadOp     = wgpu::LoadOp::Clear;
45     colorAttachment.storeOp    = wgpu::StoreOp::Store;
46     colorAttachment.clearValue = clearValue;
47 
48     return colorAttachment;
49 }
50 
CreateNewDepthStencilAttachment(float depthClearValue,uint32_t stencilClearValue,wgpu::TextureView textureView,bool hasDepthValue,bool hasStencilValue)51 wgpu::RenderPassDepthStencilAttachment CreateNewDepthStencilAttachment(
52     float depthClearValue,
53     uint32_t stencilClearValue,
54     wgpu::TextureView textureView,
55     bool hasDepthValue,
56     bool hasStencilValue)
57 {
58     wgpu::RenderPassDepthStencilAttachment depthStencilAttachment;
59     depthStencilAttachment.view = textureView;
60     // WebGPU requires that depth/stencil attachments have a load op if the correlated ReadOnly
61     // value is set to false, so we make sure to set the value here to to support cases where only a
62     // depth or stencil mask is set.
63     depthStencilAttachment.depthReadOnly   = !hasDepthValue;
64     depthStencilAttachment.stencilReadOnly = !hasStencilValue;
65     if (hasDepthValue)
66     {
67         depthStencilAttachment.depthLoadOp     = wgpu::LoadOp::Clear;
68         depthStencilAttachment.depthStoreOp    = wgpu::StoreOp::Store;
69         depthStencilAttachment.depthClearValue = depthClearValue;
70     }
71     if (hasStencilValue)
72     {
73         depthStencilAttachment.stencilLoadOp     = wgpu::LoadOp::Clear;
74         depthStencilAttachment.stencilStoreOp    = wgpu::StoreOp::Store;
75         depthStencilAttachment.stencilClearValue = stencilClearValue;
76     }
77 
78     return depthStencilAttachment;
79 }
80 
IsWgpuError(wgpu::WaitStatus waitStatus)81 bool IsWgpuError(wgpu::WaitStatus waitStatus)
82 {
83     return waitStatus != wgpu::WaitStatus::Success;
84 }
85 
IsWgpuError(WGPUBufferMapAsyncStatus mapBufferStatus)86 bool IsWgpuError(WGPUBufferMapAsyncStatus mapBufferStatus)
87 {
88     return mapBufferStatus != WGPUBufferMapAsyncStatus_Success;
89 }
90 
ClearValuesArray()91 ClearValuesArray::ClearValuesArray() : mValues{}, mEnabled{} {}
92 ClearValuesArray::~ClearValuesArray() = default;
93 
94 ClearValuesArray::ClearValuesArray(const ClearValuesArray &other)          = default;
95 ClearValuesArray &ClearValuesArray::operator=(const ClearValuesArray &rhs) = default;
96 
store(uint32_t index,const ClearValues & clearValues)97 void ClearValuesArray::store(uint32_t index, const ClearValues &clearValues)
98 {
99     mValues[index] = clearValues;
100     mEnabled.set(index);
101 }
102 
getColorMask() const103 gl::DrawBufferMask ClearValuesArray::getColorMask() const
104 {
105     return gl::DrawBufferMask(mEnabled.bits() & kUnpackedColorBuffersMask);
106 }
107 
GenerateCaps(const wgpu::Limits & limitsWgpu,gl::Caps * glCaps,gl::TextureCapsMap * glTextureCapsMap,gl::Extensions * glExtensions,gl::Limitations * glLimitations,egl::Caps * eglCaps,egl::DisplayExtensions * eglExtensions,gl::Version * maxSupportedESVersion)108 void GenerateCaps(const wgpu::Limits &limitsWgpu,
109                   gl::Caps *glCaps,
110                   gl::TextureCapsMap *glTextureCapsMap,
111                   gl::Extensions *glExtensions,
112                   gl::Limitations *glLimitations,
113                   egl::Caps *eglCaps,
114                   egl::DisplayExtensions *eglExtensions,
115                   gl::Version *maxSupportedESVersion)
116 {
117     // WebGPU does not support separate front/back stencil masks.
118     glLimitations->noSeparateStencilRefsAndMasks = true;
119 
120     // OpenGL ES extensions
121     glExtensions->debugMarkerEXT              = true;
122     glExtensions->textureUsageANGLE           = true;
123     glExtensions->translatedShaderSourceANGLE = true;
124     glExtensions->vertexArrayObjectOES        = true;
125 
126     glExtensions->textureStorageEXT = true;
127     glExtensions->rgb8Rgba8OES      = true;
128 
129     // OpenGL ES caps
130     glCaps->maxElementIndex       = std::numeric_limits<GLuint>::max() - 1;
131     glCaps->max3DTextureSize      = rx::LimitToInt(limitsWgpu.maxTextureDimension3D);
132     glCaps->max2DTextureSize      = rx::LimitToInt(limitsWgpu.maxTextureDimension2D);
133     glCaps->maxArrayTextureLayers = rx::LimitToInt(limitsWgpu.maxTextureArrayLayers);
134     glCaps->maxLODBias            = 0.0f;
135     glCaps->maxCubeMapTextureSize = rx::LimitToInt(limitsWgpu.maxTextureDimension2D);
136     glCaps->maxRenderbufferSize   = rx::LimitToInt(limitsWgpu.maxTextureDimension2D);
137     glCaps->minAliasedPointSize   = 1.0f;
138     glCaps->maxAliasedPointSize   = 1.0f;
139     glCaps->minAliasedLineWidth   = 1.0f;
140     glCaps->maxAliasedLineWidth   = 1.0f;
141 
142     // "descriptor.sampleCount must be either 1 or 4."
143     constexpr uint32_t kMaxSampleCount = 4;
144 
145     glCaps->maxDrawBuffers         = rx::LimitToInt(limitsWgpu.maxColorAttachments);
146     glCaps->maxFramebufferWidth    = rx::LimitToInt(limitsWgpu.maxTextureDimension2D);
147     glCaps->maxFramebufferHeight   = rx::LimitToInt(limitsWgpu.maxTextureDimension2D);
148     glCaps->maxFramebufferSamples  = kMaxSampleCount;
149     glCaps->maxColorAttachments    = rx::LimitToInt(limitsWgpu.maxColorAttachments);
150     glCaps->maxViewportWidth       = rx::LimitToInt(limitsWgpu.maxTextureDimension2D);
151     glCaps->maxViewportHeight      = glCaps->maxViewportWidth;
152     glCaps->maxSampleMaskWords     = 1;
153     glCaps->maxColorTextureSamples = kMaxSampleCount;
154     glCaps->maxDepthTextureSamples = kMaxSampleCount;
155     glCaps->maxIntegerSamples      = kMaxSampleCount;
156     glCaps->maxServerWaitTimeout   = 0;
157 
158     glCaps->maxVertexAttribRelativeOffset = (1u << kAttributeOffsetMaxBits) - 1;
159     glCaps->maxVertexAttribBindings =
160         rx::LimitToInt(std::min(limitsWgpu.maxVertexBuffers, limitsWgpu.maxVertexAttributes));
161     glCaps->maxVertexAttribStride =
162         rx::LimitToInt(std::min(limitsWgpu.maxVertexBufferArrayStride,
163                                 static_cast<uint32_t>(std::numeric_limits<uint16_t>::max())));
164     glCaps->maxElementsIndices    = std::numeric_limits<GLint>::max();
165     glCaps->maxElementsVertices   = std::numeric_limits<GLint>::max();
166     glCaps->vertexHighpFloat.setIEEEFloat();
167     glCaps->vertexMediumpFloat.setIEEEHalfFloat();
168     glCaps->vertexLowpFloat.setIEEEHalfFloat();
169     glCaps->fragmentHighpFloat.setIEEEFloat();
170     glCaps->fragmentMediumpFloat.setIEEEHalfFloat();
171     glCaps->fragmentLowpFloat.setIEEEHalfFloat();
172     glCaps->vertexHighpInt.setTwosComplementInt(32);
173     glCaps->vertexMediumpInt.setTwosComplementInt(16);
174     glCaps->vertexLowpInt.setTwosComplementInt(16);
175     glCaps->fragmentHighpInt.setTwosComplementInt(32);
176     glCaps->fragmentMediumpInt.setTwosComplementInt(16);
177     glCaps->fragmentLowpInt.setTwosComplementInt(16);
178 
179     // Clamp the maxUniformBlockSize to 64KB (majority of devices support up to this size
180     // currently), on AMD the maxUniformBufferRange is near uint32_t max.
181     GLuint maxUniformBlockSize = static_cast<GLuint>(
182         std::min(static_cast<uint64_t>(0x10000), limitsWgpu.maxUniformBufferBindingSize));
183 
184     const GLuint maxUniformVectors    = maxUniformBlockSize / (sizeof(GLfloat) * 4);
185     const GLuint maxUniformComponents = maxUniformVectors * 4;
186 
187     const int32_t maxPerStageUniformBuffers = rx::LimitToInt(
188         limitsWgpu.maxUniformBuffersPerShaderStage - kReservedPerStageDefaultUniformSlotCount);
189 
190     // There is no additional limit to the combined number of components.  We can have up to a
191     // maximum number of uniform buffers, each having the maximum number of components.  Note that
192     // this limit includes both components in and out of uniform buffers.
193     //
194     // This value is limited to INT_MAX to avoid overflow when queried from glGetIntegerv().
195     const uint64_t maxCombinedUniformComponents =
196         std::min<uint64_t>(static_cast<uint64_t>(maxPerStageUniformBuffers +
197                                                  kReservedPerStageDefaultUniformSlotCount) *
198                                maxUniformComponents,
199                            std::numeric_limits<GLint>::max());
200 
201     for (gl::ShaderType shaderType : gl::AllShaderTypes())
202     {
203         glCaps->maxShaderUniformBlocks[shaderType] = maxPerStageUniformBuffers;
204         glCaps->maxShaderTextureImageUnits[shaderType] =
205             rx::LimitToInt(limitsWgpu.maxSamplersPerShaderStage);
206         glCaps->maxShaderStorageBlocks[shaderType]             = 0;
207         glCaps->maxShaderUniformComponents[shaderType]         = 0;
208         glCaps->maxShaderAtomicCounterBuffers[shaderType]      = 0;
209         glCaps->maxShaderAtomicCounters[shaderType]            = 0;
210         glCaps->maxShaderImageUniforms[shaderType]             = 0;
211         glCaps->maxCombinedShaderUniformComponents[shaderType] = maxCombinedUniformComponents;
212     }
213 
214     const GLint maxVarryingComponents = rx::LimitToInt(limitsWgpu.maxInterStageShaderComponents);
215 
216     glCaps->maxVertexAttributes = rx::LimitToInt(
217         limitsWgpu.maxVertexBuffers);  // WebGPU has maxVertexBuffers and maxVertexAttributes but
218                                        // since each vertex attribute can use a unique buffer, we
219                                        // are limited by the total number of vertex buffers
220     glCaps->maxVertexUniformVectors =
221         maxUniformVectors;  // Uniforms are implemented using a uniform buffer, so the max number of
222                             // uniforms we can support is the max buffer range divided by the size
223                             // of a single uniform (4X float).
224     glCaps->maxVertexOutputComponents = maxVarryingComponents;
225 
226     glCaps->maxFragmentUniformVectors     = maxUniformVectors;
227     glCaps->maxFragmentInputComponents    = maxVarryingComponents;
228     glCaps->minProgramTextureGatherOffset = 0;
229     glCaps->maxProgramTextureGatherOffset = 0;
230     glCaps->minProgramTexelOffset         = -8;
231     glCaps->maxProgramTexelOffset         = 7;
232 
233     glCaps->maxComputeWorkGroupCount       = {0, 0, 0};
234     glCaps->maxComputeWorkGroupSize        = {0, 0, 0};
235     glCaps->maxComputeWorkGroupInvocations = 0;
236     glCaps->maxComputeSharedMemorySize     = 0;
237 
238     // Only 2 stages (vertex+fragment) are supported.
239     constexpr uint32_t kShaderStageCount = 2;
240 
241     glCaps->maxUniformBufferBindings = maxPerStageUniformBuffers * kShaderStageCount;
242     glCaps->maxUniformBlockSize      = rx::LimitToInt(limitsWgpu.maxBufferSize);
243     glCaps->uniformBufferOffsetAlignment =
244         rx::LimitToInt(limitsWgpu.minUniformBufferOffsetAlignment);
245     glCaps->maxCombinedUniformBlocks = glCaps->maxUniformBufferBindings;
246     glCaps->maxVaryingComponents     = maxVarryingComponents;
247     glCaps->maxVaryingVectors        = rx::LimitToInt(limitsWgpu.maxInterStageShaderVariables);
248     glCaps->maxCombinedTextureImageUnits =
249         rx::LimitToInt(limitsWgpu.maxSamplersPerShaderStage * kShaderStageCount);
250     glCaps->maxCombinedShaderOutputResources = 0;
251 
252     glCaps->maxUniformLocations                = maxUniformVectors;
253     glCaps->maxAtomicCounterBufferBindings     = 0;
254     glCaps->maxAtomicCounterBufferSize         = 0;
255     glCaps->maxCombinedAtomicCounterBuffers    = 0;
256     glCaps->maxCombinedAtomicCounters          = 0;
257     glCaps->maxImageUnits                      = 0;
258     glCaps->maxCombinedImageUniforms           = 0;
259     glCaps->maxShaderStorageBufferBindings     = 0;
260     glCaps->maxShaderStorageBlockSize          = 0;
261     glCaps->maxCombinedShaderStorageBlocks     = 0;
262     glCaps->shaderStorageBufferOffsetAlignment = 0;
263 
264     glCaps->maxTransformFeedbackInterleavedComponents = 0;
265     glCaps->maxTransformFeedbackSeparateAttributes    = 0;
266     glCaps->maxTransformFeedbackSeparateComponents    = 0;
267 
268     glCaps->lineWidthGranularity    = 0.0f;
269     glCaps->minMultisampleLineWidth = 0.0f;
270     glCaps->maxMultisampleLineWidth = 0.0f;
271 
272     glCaps->maxTextureBufferSize         = 0;
273     glCaps->textureBufferOffsetAlignment = 0;
274 
275     glCaps->maxSamples = kMaxSampleCount;
276 
277     // Max version
278     *maxSupportedESVersion = gl::Version(3, 2);
279 
280     // OpenGL ES texture caps
281     InitMinimumTextureCapsMap(*maxSupportedESVersion, *glExtensions, glTextureCapsMap);
282 
283     // EGL caps
284     eglCaps->textureNPOT = true;
285 
286     // EGL extensions
287     eglExtensions->createContextRobustness            = true;
288     eglExtensions->postSubBuffer                      = true;
289     eglExtensions->createContext                      = true;
290     eglExtensions->image                              = true;
291     eglExtensions->imageBase                          = true;
292     eglExtensions->glTexture2DImage                   = true;
293     eglExtensions->glTextureCubemapImage              = true;
294     eglExtensions->glTexture3DImage                   = true;
295     eglExtensions->glRenderbufferImage                = true;
296     eglExtensions->getAllProcAddresses                = true;
297     eglExtensions->noConfigContext                    = true;
298     eglExtensions->directComposition                  = true;
299     eglExtensions->createContextNoError               = true;
300     eglExtensions->createContextWebGLCompatibility    = true;
301     eglExtensions->createContextBindGeneratesResource = true;
302     eglExtensions->swapBuffersWithDamage              = true;
303     eglExtensions->pixelFormatFloat                   = true;
304     eglExtensions->surfacelessContext                 = true;
305     eglExtensions->displayTextureShareGroup           = true;
306     eglExtensions->displaySemaphoreShareGroup         = true;
307     eglExtensions->createContextClientArrays          = true;
308     eglExtensions->programCacheControlANGLE           = true;
309     eglExtensions->robustResourceInitializationANGLE  = true;
310 }
311 
IsStripPrimitiveTopology(wgpu::PrimitiveTopology topology)312 bool IsStripPrimitiveTopology(wgpu::PrimitiveTopology topology)
313 {
314     switch (topology)
315     {
316         case wgpu::PrimitiveTopology::LineStrip:
317         case wgpu::PrimitiveTopology::TriangleStrip:
318             return true;
319 
320         default:
321             return false;
322     }
323 }
324 
ErrorScope(wgpu::Instance instance,wgpu::Device device,wgpu::ErrorFilter errorType)325 ErrorScope::ErrorScope(wgpu::Instance instance, wgpu::Device device, wgpu::ErrorFilter errorType)
326     : mInstance(instance), mDevice(device)
327 {
328     mDevice.PushErrorScope(errorType);
329     mActive = true;
330 }
331 
~ErrorScope()332 ErrorScope::~ErrorScope()
333 {
334     ANGLE_UNUSED_VARIABLE(PopScope(nullptr, nullptr, nullptr, 0));
335 }
336 
PopScope(ContextWgpu * context,const char * file,const char * function,unsigned int line)337 angle::Result ErrorScope::PopScope(ContextWgpu *context,
338                                    const char *file,
339                                    const char *function,
340                                    unsigned int line)
341 {
342     if (!mActive)
343     {
344         return angle::Result::Continue;
345     }
346     mActive = false;
347 
348     bool hadError  = false;
349     wgpu::Future f = mDevice.PopErrorScope(
350         wgpu::CallbackMode::WaitAnyOnly,
351         [context, file, function, line, &hadError](wgpu::PopErrorScopeStatus status,
352                                                    wgpu::ErrorType type, char const *message) {
353             if (type == wgpu::ErrorType::NoError)
354             {
355                 return;
356             }
357 
358             if (context)
359             {
360                 ASSERT(file);
361                 ASSERT(function);
362                 context->handleError(GL_INVALID_OPERATION, message, file, function, line);
363             }
364             else
365             {
366                 ERR() << "Unhandled WebGPU error: " << message;
367             }
368             hadError = true;
369         });
370     mInstance.WaitAny(f, -1);
371 
372     return hadError ? angle::Result::Stop : angle::Result::Continue;
373 }
374 
375 }  // namespace webgpu
376 
377 namespace wgpu_gl
378 {
getLevelIndex(webgpu::LevelIndex levelWgpu,gl::LevelIndex baseLevel)379 gl::LevelIndex getLevelIndex(webgpu::LevelIndex levelWgpu, gl::LevelIndex baseLevel)
380 {
381     return gl::LevelIndex(levelWgpu.get() + baseLevel.get());
382 }
383 
getExtents(wgpu::Extent3D wgpuExtent)384 gl::Extents getExtents(wgpu::Extent3D wgpuExtent)
385 {
386     gl::Extents glExtent;
387     glExtent.width  = wgpuExtent.width;
388     glExtent.height = wgpuExtent.height;
389     glExtent.depth  = wgpuExtent.depthOrArrayLayers;
390     return glExtent;
391 }
392 }  // namespace wgpu_gl
393 
394 namespace gl_wgpu
395 {
getLevelIndex(gl::LevelIndex levelGl,gl::LevelIndex baseLevel)396 webgpu::LevelIndex getLevelIndex(gl::LevelIndex levelGl, gl::LevelIndex baseLevel)
397 {
398     ASSERT(baseLevel <= levelGl);
399     return webgpu::LevelIndex(levelGl.get() - baseLevel.get());
400 }
401 
getExtent3D(const gl::Extents & glExtent)402 wgpu::Extent3D getExtent3D(const gl::Extents &glExtent)
403 {
404     wgpu::Extent3D wgpuExtent;
405     wgpuExtent.width              = glExtent.width;
406     wgpuExtent.height             = glExtent.height;
407     wgpuExtent.depthOrArrayLayers = glExtent.depth;
408     return wgpuExtent;
409 }
410 
GetPrimitiveTopology(gl::PrimitiveMode mode)411 wgpu::PrimitiveTopology GetPrimitiveTopology(gl::PrimitiveMode mode)
412 {
413     switch (mode)
414     {
415         case gl::PrimitiveMode::Points:
416             return wgpu::PrimitiveTopology::PointList;
417         case gl::PrimitiveMode::Lines:
418             return wgpu::PrimitiveTopology::LineList;
419         case gl::PrimitiveMode::LineLoop:
420             UNIMPLEMENTED();
421             return wgpu::PrimitiveTopology::LineList;  // Emulated
422         case gl::PrimitiveMode::LineStrip:
423             return wgpu::PrimitiveTopology::LineStrip;
424         case gl::PrimitiveMode::Triangles:
425             return wgpu::PrimitiveTopology::TriangleList;
426         case gl::PrimitiveMode::TriangleStrip:
427             return wgpu::PrimitiveTopology::TriangleStrip;
428         case gl::PrimitiveMode::TriangleFan:
429             UNIMPLEMENTED();
430             return wgpu::PrimitiveTopology::TriangleList;  // Emulated
431         default:
432             UNREACHABLE();
433             return wgpu::PrimitiveTopology::Undefined;
434     }
435 }
436 
GetIndexFormat(gl::DrawElementsType drawElementsType)437 wgpu::IndexFormat GetIndexFormat(gl::DrawElementsType drawElementsType)
438 {
439     switch (drawElementsType)
440     {
441         case gl::DrawElementsType::UnsignedByte:
442             UNIMPLEMENTED();
443             return wgpu::IndexFormat::Uint16;  // Emulated
444         case gl::DrawElementsType::UnsignedShort:
445             return wgpu::IndexFormat::Uint16;
446         case gl::DrawElementsType::UnsignedInt:
447             return wgpu::IndexFormat::Uint32;
448 
449         default:
450             UNREACHABLE();
451             return wgpu::IndexFormat::Undefined;
452     }
453 }
454 
GetFrontFace(GLenum frontFace)455 wgpu::FrontFace GetFrontFace(GLenum frontFace)
456 {
457     switch (frontFace)
458     {
459         case GL_CW:
460             return wgpu::FrontFace::CW;
461         case GL_CCW:
462             return wgpu::FrontFace::CCW;
463 
464         default:
465             UNREACHABLE();
466             return wgpu::FrontFace::Undefined;
467     }
468 }
469 
GetCullMode(gl::CullFaceMode mode,bool cullFaceEnabled)470 wgpu::CullMode GetCullMode(gl::CullFaceMode mode, bool cullFaceEnabled)
471 {
472     if (!cullFaceEnabled)
473     {
474         return wgpu::CullMode::None;
475     }
476 
477     switch (mode)
478     {
479         case gl::CullFaceMode::Front:
480             return wgpu::CullMode::Front;
481         case gl::CullFaceMode::Back:
482             return wgpu::CullMode::Back;
483         case gl::CullFaceMode::FrontAndBack:
484             UNIMPLEMENTED();
485             return wgpu::CullMode::None;  // Emulated
486         default:
487             UNREACHABLE();
488             return wgpu::CullMode::None;
489     }
490 }
491 
GetColorWriteMask(bool r,bool g,bool b,bool a)492 wgpu::ColorWriteMask GetColorWriteMask(bool r, bool g, bool b, bool a)
493 {
494     return (r ? wgpu::ColorWriteMask::Red : wgpu::ColorWriteMask::None) |
495            (g ? wgpu::ColorWriteMask::Green : wgpu::ColorWriteMask::None) |
496            (b ? wgpu::ColorWriteMask::Blue : wgpu::ColorWriteMask::None) |
497            (a ? wgpu::ColorWriteMask::Alpha : wgpu::ColorWriteMask::None);
498 }
499 
getWgpuTextureDimension(gl::TextureType glTextureType)500 wgpu::TextureDimension getWgpuTextureDimension(gl::TextureType glTextureType)
501 {
502     wgpu::TextureDimension dimension = {};
503     switch (glTextureType)
504     {
505         case gl::TextureType::_2D:
506         case gl::TextureType::_2DMultisample:
507         case gl::TextureType::Rectangle:
508         case gl::TextureType::External:
509         case gl::TextureType::Buffer:
510             dimension = wgpu::TextureDimension::e2D;
511             break;
512         case gl::TextureType::_2DArray:
513         case gl::TextureType::_2DMultisampleArray:
514         case gl::TextureType::_3D:
515         case gl::TextureType::CubeMap:
516         case gl::TextureType::CubeMapArray:
517         case gl::TextureType::VideoImage:
518             dimension = wgpu::TextureDimension::e3D;
519             break;
520         default:
521             break;
522     }
523     return dimension;
524 }
525 
getCompareFunc(const GLenum glCompareFunc)526 wgpu::CompareFunction getCompareFunc(const GLenum glCompareFunc)
527 {
528     switch (glCompareFunc)
529     {
530         case GL_NEVER:
531             return wgpu::CompareFunction::Never;
532         case GL_LESS:
533             return wgpu::CompareFunction::Less;
534         case GL_EQUAL:
535             return wgpu::CompareFunction::Equal;
536         case GL_LEQUAL:
537             return wgpu::CompareFunction::LessEqual;
538         case GL_GREATER:
539             return wgpu::CompareFunction::Greater;
540         case GL_NOTEQUAL:
541             return wgpu::CompareFunction::NotEqual;
542         case GL_GEQUAL:
543             return wgpu::CompareFunction::GreaterEqual;
544         case GL_ALWAYS:
545             return wgpu::CompareFunction::Always;
546         default:
547             UNREACHABLE();
548             return wgpu::CompareFunction::Always;
549     }
550 }
551 
getStencilOp(const GLenum glStencilOp)552 wgpu::StencilOperation getStencilOp(const GLenum glStencilOp)
553 {
554     switch (glStencilOp)
555     {
556         case GL_KEEP:
557             return wgpu::StencilOperation::Keep;
558         case GL_ZERO:
559             return wgpu::StencilOperation::Zero;
560         case GL_REPLACE:
561             return wgpu::StencilOperation::Replace;
562         case GL_INCR:
563             return wgpu::StencilOperation::IncrementClamp;
564         case GL_DECR:
565             return wgpu::StencilOperation::DecrementClamp;
566         case GL_INCR_WRAP:
567             return wgpu::StencilOperation::IncrementWrap;
568         case GL_DECR_WRAP:
569             return wgpu::StencilOperation::DecrementWrap;
570         case GL_INVERT:
571             return wgpu::StencilOperation::Invert;
572         default:
573             UNREACHABLE();
574             return wgpu::StencilOperation::Keep;
575     }
576 }
577 
GetFirstIndexForDrawCall(gl::DrawElementsType indexType,const void * indices)578 uint32_t GetFirstIndexForDrawCall(gl::DrawElementsType indexType, const void *indices)
579 {
580     const size_t indexSize                = gl::GetDrawElementsTypeSize(indexType);
581     const uintptr_t indexBufferByteOffset = reinterpret_cast<uintptr_t>(indices);
582     if (indexBufferByteOffset % indexSize != 0)
583     {
584         // WebGPU only allows offsetting index buffers by multiples of the index size
585         UNIMPLEMENTED();
586     }
587 
588     return static_cast<uint32_t>(indexBufferByteOffset / indexSize);
589 }
590 
591 }  // namespace gl_wgpu
592 }  // namespace rx
593