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 #ifndef LIBANGLE_RENDERER_WGPU_WGPU_UTILS_H_
8 #define LIBANGLE_RENDERER_WGPU_WGPU_UTILS_H_
9
10 #include <dawn/webgpu_cpp.h>
11 #include <stdint.h>
12 #include <climits>
13
14 #include "libANGLE/Caps.h"
15 #include "libANGLE/Error.h"
16 #include "libANGLE/angletypes.h"
17
18 #define ANGLE_WGPU_TRY(context, command) \
19 do \
20 { \
21 auto ANGLE_LOCAL_VAR = command; \
22 if (ANGLE_UNLIKELY(::rx::webgpu::IsWgpuError(ANGLE_LOCAL_VAR))) \
23 { \
24 (context)->handleError(GL_INVALID_OPERATION, "Internal WebGPU error.", __FILE__, \
25 ANGLE_FUNCTION, __LINE__); \
26 return angle::Result::Stop; \
27 } \
28 } while (0)
29
30 #define ANGLE_WGPU_BEGIN_DEBUG_ERROR_SCOPE(context) \
31 ::rx::webgpu::DebugErrorScope(context->getInstance(), context->getDevice(), \
32 wgpu::ErrorFilter::Validation)
33 #define ANGLE_WGPU_END_DEBUG_ERROR_SCOPE(context, scope) \
34 ANGLE_TRY(scope.PopScope(context, __FILE__, ANGLE_FUNCTION, __LINE__))
35
36 #define ANGLE_WGPU_SCOPED_DEBUG_TRY(context, command) \
37 do \
38 { \
39 ::rx::webgpu::DebugErrorScope _errorScope = ANGLE_WGPU_BEGIN_DEBUG_ERROR_SCOPE(context); \
40 (command); \
41 ANGLE_WGPU_END_DEBUG_ERROR_SCOPE(context, _errorScope); \
42 } while (0)
43
44 #define ANGLE_GL_OBJECTS_X(PROC) \
45 PROC(Buffer) \
46 PROC(Context) \
47 PROC(Framebuffer) \
48 PROC(Query) \
49 PROC(Program) \
50 PROC(ProgramExecutable) \
51 PROC(Sampler) \
52 PROC(Texture) \
53 PROC(TransformFeedback) \
54 PROC(VertexArray)
55
56 #define ANGLE_EGL_OBJECTS_X(PROC) \
57 PROC(Display) \
58 PROC(Image) \
59 PROC(Surface) \
60 PROC(Sync)
61
62 namespace rx
63 {
64
65 class ContextWgpu;
66 class DisplayWgpu;
67
68 #define ANGLE_PRE_DECLARE_WGPU_OBJECT(OBJ) class OBJ##Wgpu;
69
70 ANGLE_GL_OBJECTS_X(ANGLE_PRE_DECLARE_WGPU_OBJECT)
ANGLE_EGL_OBJECTS_X(ANGLE_PRE_DECLARE_WGPU_OBJECT)71 ANGLE_EGL_OBJECTS_X(ANGLE_PRE_DECLARE_WGPU_OBJECT)
72
73 namespace webgpu
74 {
75 template <typename T>
76 struct ImplTypeHelper;
77
78 #define ANGLE_IMPL_TYPE_HELPER(frontendNamespace, OBJ) \
79 template <> \
80 struct ImplTypeHelper<frontendNamespace::OBJ> \
81 { \
82 using ImplType = rx::OBJ##Wgpu; \
83 };
84 #define ANGLE_IMPL_TYPE_HELPER_GL(OBJ) ANGLE_IMPL_TYPE_HELPER(gl, OBJ)
85 #define ANGLE_IMPL_TYPE_HELPER_EGL(OBJ) ANGLE_IMPL_TYPE_HELPER(egl, OBJ)
86
87 ANGLE_GL_OBJECTS_X(ANGLE_IMPL_TYPE_HELPER_GL)
88 ANGLE_EGL_OBJECTS_X(ANGLE_IMPL_TYPE_HELPER_EGL)
89
90 #undef ANGLE_IMPL_TYPE_HELPER_GL
91 #undef ANGLE_IMPL_TYPE_HELPER_EGL
92
93 template <typename T>
94 using GetImplType = typename ImplTypeHelper<T>::ImplType;
95
96 template <typename T>
97 GetImplType<T> *GetImpl(const T *glObject)
98 {
99 return GetImplAs<GetImplType<T>>(glObject);
100 }
101
102 constexpr size_t kUnpackedDepthIndex = gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
103 constexpr size_t kUnpackedStencilIndex = gl::IMPLEMENTATION_MAX_DRAW_BUFFERS + 1;
104 constexpr uint32_t kUnpackedColorBuffersMask =
105 angle::BitMask<uint32_t>(gl::IMPLEMENTATION_MAX_DRAW_BUFFERS);
106 // WebGPU image level index.
107 using LevelIndex = gl::LevelIndexWrapper<uint32_t>;
108
109 class ErrorScope : public angle::NonCopyable
110 {
111 public:
112 ErrorScope(wgpu::Instance instance, wgpu::Device device, wgpu::ErrorFilter errorType);
113 ~ErrorScope();
114
115 angle::Result PopScope(ContextWgpu *context,
116 const char *file,
117 const char *function,
118 unsigned int line);
119
120 private:
121 wgpu::Instance mInstance;
122 wgpu::Device mDevice;
123 bool mActive = false;
124 };
125
126 class NoOpErrorScope : public angle::NonCopyable
127 {
128 public:
129 NoOpErrorScope(wgpu::Instance instance, wgpu::Device device, wgpu::ErrorFilter errorType) {}
130 ~NoOpErrorScope() {}
131
132 angle::Result PopScope(ContextWgpu *context,
133 const char *file,
134 const char *function,
135 unsigned int line)
136 {
137 return angle::Result::Continue;
138 }
139 };
140
141 #if defined(ANGLE_ENABLE_ASSERTS)
142 using DebugErrorScope = ErrorScope;
143 #else
144 using DebugErrorScope = NoOpErrorScope;
145 #endif
146
147 enum class RenderPassClosureReason
148 {
149 NewRenderPass,
150 FramebufferBindingChange,
151 FramebufferInternalChange,
152 GLFlush,
153 GLFinish,
154 EGLSwapBuffers,
155 GLReadPixels,
156 IndexRangeReadback,
157 VertexArrayStreaming,
158 VertexArrayLineLoop,
159
160 InvalidEnum,
161 EnumCount = InvalidEnum,
162 };
163
164 struct ClearValues
165 {
166 wgpu::Color clearColor;
167 uint32_t depthSlice;
168 float depthValue;
169 uint32_t stencilValue;
170 };
171
172 class ClearValuesArray final
173 {
174 public:
175 ClearValuesArray();
176 ~ClearValuesArray();
177
178 ClearValuesArray(const ClearValuesArray &other);
179 ClearValuesArray &operator=(const ClearValuesArray &rhs);
180
181 void store(uint32_t index, const ClearValues &clearValues);
182
183 gl::DrawBufferMask getColorMask() const;
184 void reset()
185 {
186 mValues.fill({});
187 mEnabled.reset();
188 }
189 void reset(size_t index)
190 {
191 mValues[index] = {};
192 mEnabled.reset(index);
193 }
194 void resetDepth()
195 {
196 mValues[kUnpackedDepthIndex] = {};
197 mEnabled.reset(kUnpackedDepthIndex);
198 }
199 void resetStencil()
200 {
201 mValues[kUnpackedStencilIndex] = {};
202 mEnabled.reset(kUnpackedStencilIndex);
203 }
204 const ClearValues &operator[](size_t index) const { return mValues[index]; }
205
206 bool empty() const { return mEnabled.none(); }
207 bool any() const { return mEnabled.any(); }
208
209 bool test(size_t index) const { return mEnabled.test(index); }
210
211 float getDepthValue() const { return mValues[kUnpackedDepthIndex].depthValue; }
212 uint32_t getStencilValue() const { return mValues[kUnpackedStencilIndex].stencilValue; }
213 bool hasDepth() const { return mEnabled.test(kUnpackedDepthIndex); }
214 bool hasStencil() const { return mEnabled.test(kUnpackedStencilIndex); }
215
216 private:
217 gl::AttachmentArray<ClearValues> mValues;
218 gl::AttachmentsMask mEnabled;
219 };
220
221 void GenerateCaps(const wgpu::Limits &limitWgpu,
222 gl::Caps *glCaps,
223 gl::TextureCapsMap *glTextureCapsMap,
224 gl::Extensions *glExtensions,
225 gl::Limitations *glLimitations,
226 egl::Caps *eglCaps,
227 egl::DisplayExtensions *eglExtensions,
228 gl::Version *maxSupportedESVersion);
229
230 DisplayWgpu *GetDisplay(const gl::Context *context);
231 wgpu::Device GetDevice(const gl::Context *context);
232 wgpu::Instance GetInstance(const gl::Context *context);
233 wgpu::RenderPassColorAttachment CreateNewClearColorAttachment(wgpu::Color clearValue,
234 uint32_t depthSlice,
235 wgpu::TextureView textureView);
236 wgpu::RenderPassDepthStencilAttachment CreateNewDepthStencilAttachment(
237 float depthClearValue,
238 uint32_t stencilClearValue,
239 wgpu::TextureView textureView,
240 bool hasDepthValue = false,
241 bool hasStencilValue = false);
242
243 bool IsWgpuError(wgpu::WaitStatus waitStatus);
244 bool IsWgpuError(wgpu::MapAsyncStatus mapAsyncStatus);
245
246 bool IsStripPrimitiveTopology(wgpu::PrimitiveTopology topology);
247
248 // Required alignments for buffer sizes and mapping
249 constexpr size_t kBufferSizeAlignment = 4;
250 constexpr size_t kBufferCopyToBufferAlignment = 4;
251 constexpr size_t kBufferMapSizeAlignment = kBufferSizeAlignment;
252 constexpr size_t kBufferMapOffsetAlignment = 8;
253
254 // Required alignments for texture row uploads
255 constexpr size_t kTextureRowSizeAlignment = 256;
256
257 } // namespace webgpu
258
259 namespace wgpu_gl
260 {
261 gl::LevelIndex getLevelIndex(webgpu::LevelIndex levelWgpu, gl::LevelIndex baseLevel);
262 gl::Extents getExtents(wgpu::Extent3D wgpuExtent);
263 } // namespace wgpu_gl
264
265 namespace gl_wgpu
266 {
267 webgpu::LevelIndex getLevelIndex(gl::LevelIndex levelGl, gl::LevelIndex baseLevel);
268 wgpu::TextureDimension getWgpuTextureDimension(gl::TextureType glTextureType);
269 wgpu::Extent3D getExtent3D(const gl::Extents &glExtent);
270
271 wgpu::PrimitiveTopology GetPrimitiveTopology(gl::PrimitiveMode mode);
272
273 wgpu::IndexFormat GetIndexFormat(gl::DrawElementsType drawElementsTYpe);
274 wgpu::FrontFace GetFrontFace(GLenum frontFace);
275 wgpu::CullMode GetCullMode(gl::CullFaceMode mode, bool cullFaceEnabled);
276 wgpu::ColorWriteMask GetColorWriteMask(bool r, bool g, bool b, bool a);
277
278 wgpu::BlendFactor GetBlendFactor(gl::BlendFactorType blendFactor);
279 wgpu::BlendOperation GetBlendEquation(gl::BlendEquationType blendEquation);
280
281 wgpu::CompareFunction GetCompareFunc(const GLenum glCompareFunc, bool testEnabled);
282 wgpu::StencilOperation getStencilOp(const GLenum glStencilOp);
283
284 uint32_t GetFirstIndexForDrawCall(gl::DrawElementsType indexType, const void *indices);
285 } // namespace gl_wgpu
286
287 // Number of reserved binding slots to implement the default uniform block
288 constexpr uint32_t kReservedPerStageDefaultUniformSlotCount = 0;
289
290 } // namespace rx
291
292 #define ANGLE_WGPU_WRAPPER_OBJECTS_X(PROC) \
293 PROC(BindGroup) \
294 PROC(Buffer) \
295 PROC(RenderPipeline)
296
297 // Add a hash function for all wgpu cpp wrappers that hashes the underlying C object pointer.
298 #define ANGLE_WGPU_WRAPPER_OBJECT_HASH(OBJ) \
299 namespace std \
300 { \
301 template <> \
302 struct hash<wgpu::OBJ> \
303 { \
304 size_t operator()(const wgpu::OBJ &wrapper) const \
305 { \
306 std::hash<decltype(wrapper.Get())> cTypeHash; \
307 return cTypeHash(wrapper.Get()); \
308 } \
309 }; \
310 }
311
312 ANGLE_WGPU_WRAPPER_OBJECTS_X(ANGLE_WGPU_WRAPPER_OBJECT_HASH)
313 #undef ANGLE_WGPU_WRAPPER_OBJECT_HASH
314
315 // Add a hash function for all wgpu cpp wrappers that compares the underlying C object pointer.
316 #define ANGLE_WGPU_WRAPPER_OBJECT_EQUALITY(OBJ) \
317 namespace wgpu \
318 { \
319 inline bool operator==(const OBJ &a, const OBJ &b) \
320 { \
321 return a.Get() == b.Get(); \
322 } \
323 }
324
325 ANGLE_WGPU_WRAPPER_OBJECTS_X(ANGLE_WGPU_WRAPPER_OBJECT_EQUALITY)
326 #undef ANGLE_WGPU_WRAPPER_OBJECT_EQUALITY
327
328 #undef ANGLE_WGPU_WRAPPER_OBJECTS_X
329
330 #endif // LIBANGLE_RENDERER_WGPU_WGPU_UTILS_H_
331