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
159 InvalidEnum,
160 EnumCount = InvalidEnum,
161 };
162
163 struct ClearValues
164 {
165 wgpu::Color clearColor;
166 uint32_t depthSlice;
167 float depthValue;
168 uint32_t stencilValue;
169 };
170
171 class ClearValuesArray final
172 {
173 public:
174 ClearValuesArray();
175 ~ClearValuesArray();
176
177 ClearValuesArray(const ClearValuesArray &other);
178 ClearValuesArray &operator=(const ClearValuesArray &rhs);
179
180 void store(uint32_t index, const ClearValues &clearValues);
181
182 gl::DrawBufferMask getColorMask() const;
183 void reset()
184 {
185 mValues.fill({});
186 mEnabled.reset();
187 }
188 void reset(size_t index)
189 {
190 mValues[index] = {};
191 mEnabled.reset(index);
192 }
193 void resetDepth()
194 {
195 mValues[kUnpackedDepthIndex] = {};
196 mEnabled.reset(kUnpackedDepthIndex);
197 }
198 void resetStencil()
199 {
200 mValues[kUnpackedStencilIndex] = {};
201 mEnabled.reset(kUnpackedStencilIndex);
202 }
203 const ClearValues &operator[](size_t index) const { return mValues[index]; }
204
205 bool empty() const { return mEnabled.none(); }
206 bool any() const { return mEnabled.any(); }
207
208 bool test(size_t index) const { return mEnabled.test(index); }
209
210 float getDepthValue() const { return mValues[kUnpackedDepthIndex].depthValue; }
211 uint32_t getStencilValue() const { return mValues[kUnpackedStencilIndex].stencilValue; }
212 bool hasDepth() const { return mEnabled.test(kUnpackedDepthIndex); }
213 bool hasStencil() const { return mEnabled.test(kUnpackedStencilIndex); }
214
215 private:
216 gl::AttachmentArray<ClearValues> mValues;
217 gl::AttachmentsMask mEnabled;
218 };
219
220 void GenerateCaps(const wgpu::Limits &limitWgpu,
221 gl::Caps *glCaps,
222 gl::TextureCapsMap *glTextureCapsMap,
223 gl::Extensions *glExtensions,
224 gl::Limitations *glLimitations,
225 egl::Caps *eglCaps,
226 egl::DisplayExtensions *eglExtensions,
227 gl::Version *maxSupportedESVersion);
228
229 DisplayWgpu *GetDisplay(const gl::Context *context);
230 wgpu::Device GetDevice(const gl::Context *context);
231 wgpu::Instance GetInstance(const gl::Context *context);
232 wgpu::RenderPassColorAttachment CreateNewClearColorAttachment(wgpu::Color clearValue,
233 uint32_t depthSlice,
234 wgpu::TextureView textureView);
235 wgpu::RenderPassDepthStencilAttachment CreateNewDepthStencilAttachment(
236 float depthClearValue,
237 uint32_t stencilClearValue,
238 wgpu::TextureView textureView,
239 bool hasDepthValue = false,
240 bool hasStencilValue = false);
241
242 bool IsWgpuError(wgpu::WaitStatus waitStatus);
243 bool IsWgpuError(WGPUBufferMapAsyncStatus mapBufferStatus);
244
245 bool IsStripPrimitiveTopology(wgpu::PrimitiveTopology topology);
246
247 // Required alignments for buffer sizes and mapping
248 constexpr size_t kBufferSizeAlignment = 4;
249 constexpr size_t kBufferCopyToBufferAlignment = 4;
250 constexpr size_t kBufferMapSizeAlignment = kBufferSizeAlignment;
251 constexpr size_t kBufferMapOffsetAlignment = 8;
252
253 // Required alignments for texture row uploads
254 constexpr size_t kTextureRowSizeAlignment = 256;
255
256 } // namespace webgpu
257
258 namespace wgpu_gl
259 {
260 gl::LevelIndex getLevelIndex(webgpu::LevelIndex levelWgpu, gl::LevelIndex baseLevel);
261 gl::Extents getExtents(wgpu::Extent3D wgpuExtent);
262 } // namespace wgpu_gl
263
264 namespace gl_wgpu
265 {
266 webgpu::LevelIndex getLevelIndex(gl::LevelIndex levelGl, gl::LevelIndex baseLevel);
267 wgpu::TextureDimension getWgpuTextureDimension(gl::TextureType glTextureType);
268 wgpu::Extent3D getExtent3D(const gl::Extents &glExtent);
269
270 wgpu::PrimitiveTopology GetPrimitiveTopology(gl::PrimitiveMode mode);
271
272 wgpu::IndexFormat GetIndexFormat(gl::DrawElementsType drawElementsTYpe);
273 wgpu::FrontFace GetFrontFace(GLenum frontFace);
274 wgpu::CullMode GetCullMode(gl::CullFaceMode mode, bool cullFaceEnabled);
275 wgpu::ColorWriteMask GetColorWriteMask(bool r, bool g, bool b, bool a);
276
277 wgpu::CompareFunction getCompareFunc(const GLenum glCompareFunc);
278 wgpu::StencilOperation getStencilOp(const GLenum glStencilOp);
279
280 uint32_t GetFirstIndexForDrawCall(gl::DrawElementsType indexType, const void *indices);
281 } // namespace gl_wgpu
282
283 // Number of reserved binding slots to implement the default uniform block
284 constexpr uint32_t kReservedPerStageDefaultUniformSlotCount = 0;
285
286 } // namespace rx
287
288 #define ANGLE_WGPU_WRAPPER_OBJECTS_X(PROC) \
289 PROC(BindGroup) \
290 PROC(Buffer) \
291 PROC(RenderPipeline)
292
293 // Add a hash function for all wgpu cpp wrappers that hashes the underlying C object pointer.
294 #define ANGLE_WGPU_WRAPPER_OBJECT_HASH(OBJ) \
295 namespace std \
296 { \
297 template <> \
298 struct hash<wgpu::OBJ> \
299 { \
300 size_t operator()(const wgpu::OBJ &wrapper) const \
301 { \
302 std::hash<decltype(wrapper.Get())> cTypeHash; \
303 return cTypeHash(wrapper.Get()); \
304 } \
305 }; \
306 }
307
308 ANGLE_WGPU_WRAPPER_OBJECTS_X(ANGLE_WGPU_WRAPPER_OBJECT_HASH)
309 #undef ANGLE_WGPU_WRAPPER_OBJECT_HASH
310
311 // Add a hash function for all wgpu cpp wrappers that compares the underlying C object pointer.
312 #define ANGLE_WGPU_WRAPPER_OBJECT_EQUALITY(OBJ) \
313 namespace wgpu \
314 { \
315 inline bool operator==(const OBJ &a, const OBJ &b) \
316 { \
317 return a.Get() == b.Get(); \
318 } \
319 }
320
321 ANGLE_WGPU_WRAPPER_OBJECTS_X(ANGLE_WGPU_WRAPPER_OBJECT_EQUALITY)
322 #undef ANGLE_WGPU_WRAPPER_OBJECT_EQUALITY
323
324 #undef ANGLE_WGPU_WRAPPER_OBJECTS_X
325
326 #endif // LIBANGLE_RENDERER_WGPU_WGPU_UTILS_H_
327