• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Dawn Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef DAWN_NODE_BINDING_CONVERTER_H_
16 #define DAWN_NODE_BINDING_CONVERTER_H_
17 
18 #include <functional>
19 #include <type_traits>
20 
21 #include "dawn/webgpu_cpp.h"
22 #include "dawn_native/DawnNative.h"
23 #include "napi.h"
24 #include "src/dawn_node/binding/Errors.h"
25 #include "src/dawn_node/interop/WebGPU.h"
26 
27 namespace wgpu { namespace binding {
28 
29     // ImplOfTraits is a traits helper that is used to associate the interop interface type to the
30     // binding implementation type.
31     template <typename T>
32     struct ImplOfTraits {};
33 
34     // DECLARE_IMPL() is a macro that declares a specialization of ImplOfTraits so that
35     // `typename ImplOfTraits<interop::NAME>::type` is equivalent to `binding::NAME`.
36 #define DECLARE_IMPL(NAME)               \
37     class NAME;                          \
38     template <>                          \
39     struct ImplOfTraits<interop::NAME> { \
40         using type = binding::NAME;      \
41     }
42 
43     // Declare the interop interface to binding implementations
44     DECLARE_IMPL(GPUBindGroup);
45     DECLARE_IMPL(GPUBindGroupLayout);
46     DECLARE_IMPL(GPUBuffer);
47     DECLARE_IMPL(GPUPipelineLayout);
48     DECLARE_IMPL(GPUQuerySet);
49     DECLARE_IMPL(GPURenderBundle);
50     DECLARE_IMPL(GPURenderPipeline);
51     DECLARE_IMPL(GPUSampler);
52     DECLARE_IMPL(GPUShaderModule);
53     DECLARE_IMPL(GPUTexture);
54     DECLARE_IMPL(GPUTextureView);
55 #undef DECLARE_IMPL
56 
57     // Helper for obtaining the binding implementation type from the interop interface type
58     template <typename T>
59     using ImplOf = typename ImplOfTraits<T>::type;
60 
61     // Converter is a utility class for converting IDL generated interop types into Dawn types.
62     // As the Dawn C++ API uses raw C pointers for a number of its interfaces, Converter performs
63     // heap allocations for conversions of vector or optional types. These pointers are
64     // automatically freed when the Converter is destructed.
65     class Converter {
66       public:
Converter(Napi::Env e)67         Converter(Napi::Env e) : env(e) {
68         }
69         ~Converter();
70 
71         // Conversion function. Converts the interop type IN to the Dawn type OUT.
72         // Returns true on success, false on failure.
73         template <typename OUT, typename IN>
operator()74         [[nodiscard]] inline bool operator()(OUT&& out, IN&& in) {
75             return Convert(std::forward<OUT>(out), std::forward<IN>(in));
76         }
77 
78         // Vector conversion function. Converts the vector of interop type IN to a pointer of
79         // elements of Dawn type OUT, which is assigned to 'out_els'.
80         // out_count is assigned the number of elements in 'in'.
81         // Returns true on success, false on failure.
82         // The pointer assigned to 'out_els' is valid until the Converter is destructed.
83         template <typename OUT, typename IN>
operator()84         [[nodiscard]] inline bool operator()(OUT*& out_els,
85                                              uint32_t& out_count,
86                                              const std::vector<IN>& in) {
87             return Convert(out_els, out_count, in);
88         }
89 
90         // Returns the Env that this Converter was constructed with.
Env()91         inline Napi::Env Env() const {
92             return env;
93         }
94 
95         // BufferSource is the converted type of interop::BufferSource.
96         struct BufferSource {
97             void* data;
98             size_t size;
99         };
100 
101       private:
102         // Below are the various overloads of Convert() used to convert the interop -> Dawn types.
103         [[nodiscard]] bool Convert(wgpu::Extent3D& out, const interop::GPUExtent3D& in);
104 
105         [[nodiscard]] bool Convert(wgpu::Origin3D& out, const interop::GPUOrigin3DDict& in);
106 
107         [[nodiscard]] bool Convert(wgpu::Color& out, const interop::GPUColor& in);
108 
109         [[nodiscard]] bool Convert(wgpu::Origin3D& out,
110                                    const std::vector<interop::GPUIntegerCoordinate>& in);
111 
112         [[nodiscard]] bool Convert(wgpu::TextureAspect& out, const interop::GPUTextureAspect& in);
113 
114         [[nodiscard]] bool Convert(wgpu::ImageCopyTexture& out,
115                                    const interop::GPUImageCopyTexture& in);
116 
117         [[nodiscard]] bool Convert(wgpu::ImageCopyBuffer& out,
118                                    const interop::GPUImageCopyBuffer& in);
119 
120         [[nodiscard]] bool Convert(BufferSource& out, interop::BufferSource in);
121 
122         [[nodiscard]] bool Convert(wgpu::TextureDataLayout& out,
123                                    const interop::GPUImageDataLayout& in);
124 
125         [[nodiscard]] bool Convert(wgpu::TextureFormat& out, const interop::GPUTextureFormat& in);
126 
127         [[nodiscard]] bool Convert(wgpu::TextureUsage& out,
128                                    const interop::GPUTextureUsageFlags& in);
129 
130         [[nodiscard]] bool Convert(wgpu::ColorWriteMask& out,
131                                    const interop::GPUColorWriteFlags& in);
132 
133         [[nodiscard]] bool Convert(wgpu::BufferUsage& out, const interop::GPUBufferUsageFlags& in);
134 
135         [[nodiscard]] bool Convert(wgpu::MapMode& out, const interop::GPUMapModeFlags& in);
136 
137         [[nodiscard]] bool Convert(wgpu::ShaderStage& out, const interop::GPUShaderStageFlags& in);
138 
139         [[nodiscard]] bool Convert(wgpu::TextureDimension& out,
140                                    const interop::GPUTextureDimension& in);
141 
142         [[nodiscard]] bool Convert(wgpu::TextureViewDimension& out,
143                                    const interop::GPUTextureViewDimension& in);
144 
145         [[nodiscard]] bool Convert(wgpu::ProgrammableStageDescriptor& out,
146                                    const interop::GPUProgrammableStage& in);
147 
148         [[nodiscard]] bool Convert(wgpu::ConstantEntry& out,
149                                    const std::string& in_name,
150                                    wgpu::interop::GPUPipelineConstantValue in_value);
151 
152         [[nodiscard]] bool Convert(wgpu::BlendComponent& out, const interop::GPUBlendComponent& in);
153 
154         [[nodiscard]] bool Convert(wgpu::BlendFactor& out, const interop::GPUBlendFactor& in);
155 
156         [[nodiscard]] bool Convert(wgpu::BlendOperation& out, const interop::GPUBlendOperation& in);
157 
158         [[nodiscard]] bool Convert(wgpu::BlendState& out, const interop::GPUBlendState& in);
159 
160         [[nodiscard]] bool Convert(wgpu::PrimitiveState& out, const interop::GPUPrimitiveState& in);
161 
162         [[nodiscard]] bool Convert(wgpu::ColorTargetState& out,
163                                    const interop::GPUColorTargetState& in);
164 
165         [[nodiscard]] bool Convert(wgpu::DepthStencilState& out,
166                                    const interop::GPUDepthStencilState& in);
167 
168         [[nodiscard]] bool Convert(wgpu::MultisampleState& out,
169                                    const interop::GPUMultisampleState& in);
170 
171         [[nodiscard]] bool Convert(wgpu::FragmentState& out, const interop::GPUFragmentState& in);
172 
173         [[nodiscard]] bool Convert(wgpu::PrimitiveTopology& out,
174                                    const interop::GPUPrimitiveTopology& in);
175 
176         [[nodiscard]] bool Convert(wgpu::FrontFace& out, const interop::GPUFrontFace& in);
177 
178         [[nodiscard]] bool Convert(wgpu::CullMode& out, const interop::GPUCullMode& in);
179 
180         [[nodiscard]] bool Convert(wgpu::CompareFunction& out,
181                                    const interop::GPUCompareFunction& in);
182 
183         [[nodiscard]] bool Convert(wgpu::IndexFormat& out, const interop::GPUIndexFormat& in);
184 
185         [[nodiscard]] bool Convert(wgpu::StencilOperation& out,
186                                    const interop::GPUStencilOperation& in);
187 
188         [[nodiscard]] bool Convert(wgpu::StencilFaceState& out,
189                                    const interop::GPUStencilFaceState& in);
190 
191         [[nodiscard]] bool Convert(wgpu::VertexState& out, const interop::GPUVertexState& in);
192 
193         [[nodiscard]] bool Convert(wgpu::VertexBufferLayout& out,
194                                    const interop::GPUVertexBufferLayout& in);
195 
196         [[nodiscard]] bool Convert(wgpu::VertexStepMode& out, const interop::GPUVertexStepMode& in);
197 
198         [[nodiscard]] bool Convert(wgpu::VertexAttribute& out,
199                                    const interop::GPUVertexAttribute& in);
200 
201         [[nodiscard]] bool Convert(wgpu::VertexFormat& out, const interop::GPUVertexFormat& in);
202 
203         [[nodiscard]] bool Convert(wgpu::RenderPassColorAttachment& out,
204                                    const interop::GPURenderPassColorAttachment& in);
205 
206         [[nodiscard]] bool Convert(wgpu::RenderPassDepthStencilAttachment& out,
207                                    const interop::GPURenderPassDepthStencilAttachment& in);
208 
209         [[nodiscard]] bool Convert(wgpu::LoadOp& out, const interop::GPULoadOp& in);
210 
211         [[nodiscard]] bool Convert(wgpu::StoreOp& out, const interop::GPUStoreOp& in);
212 
213         [[nodiscard]] bool Convert(wgpu::BindGroupEntry& out, const interop::GPUBindGroupEntry& in);
214 
215         [[nodiscard]] bool Convert(wgpu::BindGroupLayoutEntry& out,
216                                    const interop::GPUBindGroupLayoutEntry& in);
217 
218         [[nodiscard]] bool Convert(wgpu::BufferBindingLayout& out,
219                                    const interop::GPUBufferBindingLayout& in);
220 
221         [[nodiscard]] bool Convert(wgpu::SamplerBindingLayout& out,
222                                    const interop::GPUSamplerBindingLayout& in);
223 
224         [[nodiscard]] bool Convert(wgpu::TextureBindingLayout& out,
225                                    const interop::GPUTextureBindingLayout& in);
226 
227         [[nodiscard]] bool Convert(wgpu::StorageTextureBindingLayout& out,
228                                    const interop::GPUStorageTextureBindingLayout& in);
229 
230         [[nodiscard]] bool Convert(wgpu::BufferBindingType& out,
231                                    const interop::GPUBufferBindingType& in);
232 
233         [[nodiscard]] bool Convert(wgpu::SamplerBindingType& out,
234                                    const interop::GPUSamplerBindingType& in);
235 
236         [[nodiscard]] bool Convert(wgpu::TextureSampleType& out,
237                                    const interop::GPUTextureSampleType& in);
238 
239         [[nodiscard]] bool Convert(wgpu::StorageTextureAccess& out,
240                                    const interop::GPUStorageTextureAccess& in);
241 
242         [[nodiscard]] bool Convert(wgpu::QueryType& out, const interop::GPUQueryType& in);
243 
244         [[nodiscard]] bool Convert(wgpu::PipelineStatisticName& out,
245                                    const interop::GPUPipelineStatisticName& in);
246 
247         [[nodiscard]] bool Convert(wgpu::AddressMode& out, const interop::GPUAddressMode& in);
248 
249         [[nodiscard]] bool Convert(wgpu::FilterMode& out, const interop::GPUFilterMode& in);
250 
251         [[nodiscard]] bool Convert(wgpu::ComputePipelineDescriptor& out,
252                                    const interop::GPUComputePipelineDescriptor& in);
253 
254         [[nodiscard]] bool Convert(wgpu::RenderPipelineDescriptor& out,
255                                    const interop::GPURenderPipelineDescriptor& in);
256 
257         // std::string to C string
Convert(const char * & out,const std::string & in)258         inline bool Convert(const char*& out, const std::string& in) {
259             out = in.c_str();
260             return true;
261         }
262 
263         // Pass-through (no conversion)
264         template <typename T>
Convert(T & out,const T & in)265         inline bool Convert(T& out, const T& in) {
266             out = in;
267             return true;
268         }
269 
270         // Integral number conversion, with dynamic limit checking
271         template <typename OUT,
272                   typename IN,
273                   typename = std::enable_if_t<std::is_integral_v<IN> && std::is_integral_v<OUT>>>
Convert(OUT & out,const IN & in)274         inline bool Convert(OUT& out, const IN& in) {
275             out = static_cast<OUT>(in);
276             if (static_cast<IN>(out) != in) {
277                 Napi::Error::New(env, "Integer value (" + std::to_string(in) +
278                                           ") cannot be converted to the Dawn data type without "
279                                           "truncation of the value")
280                     .ThrowAsJavaScriptException();
281                 return false;
282             }
283             return true;
284         }
285 
286         template <typename OUT, typename... IN_TYPES>
Convert(OUT & out,const std::variant<IN_TYPES...> & in)287         inline bool Convert(OUT& out, const std::variant<IN_TYPES...>& in) {
288             return std::visit([&](auto&& i) { return Convert(out, i); }, in);
289         }
290 
291         // If the std::optional does not have a value, then Convert() simply returns true and 'out'
292         // is not assigned a new value.
293         template <typename OUT, typename IN>
Convert(OUT & out,const std::optional<IN> & in)294         inline bool Convert(OUT& out, const std::optional<IN>& in) {
295             if (in.has_value()) {
296                 return Convert(out, in.value());
297             }
298             return true;
299         }
300 
301         // std::optional -> T*
302         // OUT* is assigned either a pointer to the converted value, or nullptr, depending on
303         // whether 'in' has a value.
304         template <typename OUT,
305                   typename IN,
306                   typename _ = std::enable_if_t<!std::is_same_v<IN, std::string>>>
Convert(OUT * & out,const std::optional<IN> & in)307         inline bool Convert(OUT*& out, const std::optional<IN>& in) {
308             if (in.has_value()) {
309                 auto* el = Allocate<std::remove_const_t<OUT>>();
310                 if (!Convert(*el, in.value())) {
311                     return false;
312                 }
313                 out = el;
314             } else {
315                 out = nullptr;
316             }
317             return true;
318         }
319 
320         // interop::Interface -> Dawn object
321         template <typename OUT, typename IN>
Convert(OUT & out,const interop::Interface<IN> & in)322         inline bool Convert(OUT& out, const interop::Interface<IN>& in) {
323             using Impl = ImplOf<IN>;
324             out = *in.template As<Impl>();
325             if (!out) {
326                 LOG("Dawn object has been destroyed. This should not happen");
327                 return false;
328             }
329             return true;
330         }
331 
332         // vector -> raw pointer + count
333         template <typename OUT, typename IN>
Convert(OUT * & out_els,uint32_t & out_count,const std::vector<IN> & in)334         inline bool Convert(OUT*& out_els, uint32_t& out_count, const std::vector<IN>& in) {
335             if (in.size() == 0) {
336                 out_els = nullptr;
337                 out_count = 0;
338                 return true;
339             }
340             auto* els = Allocate<std::remove_const_t<OUT>>(in.size());
341             for (size_t i = 0; i < in.size(); i++) {
342                 if (!Convert(els[i], in[i])) {
343                     return false;
344                 }
345             }
346             out_els = els;
347             return Convert(out_count, in.size());
348         }
349 
350         // unordered_map -> raw pointer + count
351         template <typename OUT, typename IN_KEY, typename IN_VALUE>
Convert(OUT * & out_els,uint32_t & out_count,const std::unordered_map<IN_KEY,IN_VALUE> & in)352         inline bool Convert(OUT*& out_els,
353                             uint32_t& out_count,
354                             const std::unordered_map<IN_KEY, IN_VALUE>& in) {
355             if (in.size() == 0) {
356                 out_els = nullptr;
357                 out_count = 0;
358                 return true;
359             }
360             auto* els = Allocate<std::remove_const_t<OUT>>(in.size());
361             size_t i = 0;
362             for (auto& it : in) {
363                 if (!Convert(els[i++], it.first, it.second)) {
364                     return false;
365                 }
366             }
367             out_els = els;
368             return Convert(out_count, in.size());
369         }
370 
371         // std::optional<T> -> raw pointer + count
372         template <typename OUT, typename IN>
Convert(OUT * & out_els,uint32_t & out_count,const std::optional<IN> & in)373         inline bool Convert(OUT*& out_els, uint32_t& out_count, const std::optional<IN>& in) {
374             if (!in.has_value()) {
375                 out_els = nullptr;
376                 out_count = 0;
377                 return true;
378             }
379             return Convert(out_els, out_count, in.value());
380         }
381 
382         Napi::Env env;
383 
384         // Allocate() allocates and constructs an array of 'n' elements, and returns a pointer to
385         // the first element. The array is freed when the Converter is destructed.
386         template <typename T>
387         T* Allocate(size_t n = 1) {
388             auto* ptr = new T[n]{};
389             free_.emplace_back([ptr] { delete[] ptr; });
390             return ptr;
391         }
392 
393         std::vector<std::function<void()>> free_;
394     };
395 
396 }}  // namespace wgpu::binding
397 
398 #endif  // DAWN_NODE_BINDING_CONVERTER_H_
399