• 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 #include "src/dawn_node/binding/GPU.h"
16 
17 #include "src/dawn_node/binding/GPUAdapter.h"
18 
19 #include <cstdlib>
20 
21 #if defined(_WIN32)
22 #    include <Windows.h>
23 #endif
24 
25 namespace {
GetEnvVar(const char * varName)26     std::string GetEnvVar(const char* varName) {
27 #if defined(_WIN32)
28         // Use _dupenv_s to avoid unsafe warnings about std::getenv
29         char* value = nullptr;
30         _dupenv_s(&value, nullptr, varName);
31         if (value) {
32             std::string result = value;
33             free(value);
34             return result;
35         }
36         return "";
37 #else
38         if (auto* val = std::getenv(varName)) {
39             return val;
40         }
41         return "";
42 #endif
43     }
44 
SetDllDir(const char * dir)45     void SetDllDir(const char* dir) {
46         (void)dir;
47 #if defined(_WIN32)
48         ::SetDllDirectory(dir);
49 #endif
50     }
51 
52 }  // namespace
53 
54 namespace wgpu { namespace binding {
55 
56     ////////////////////////////////////////////////////////////////////////////////
57     // wgpu::bindings::GPU
58     ////////////////////////////////////////////////////////////////////////////////
GPU(Flags flags)59     GPU::GPU(Flags flags) : flags_(std::move(flags)) {
60         // TODO: Disable in 'release'
61         instance_.EnableBackendValidation(true);
62         instance_.SetBackendValidationLevel(dawn_native::BackendValidationLevel::Full);
63 
64         // Setting the DllDir changes where we load adapter DLLs from (e.g. d3dcompiler_47.dll)
65         if (auto dir = flags_.Get("dlldir")) {
66             SetDllDir(dir->c_str());
67         }
68         instance_.DiscoverDefaultAdapters();
69     }
70 
requestAdapter(Napi::Env env,interop::GPURequestAdapterOptions options)71     interop::Promise<std::optional<interop::Interface<interop::GPUAdapter>>> GPU::requestAdapter(
72         Napi::Env env,
73         interop::GPURequestAdapterOptions options) {
74         auto promise = interop::Promise<std::optional<interop::Interface<interop::GPUAdapter>>>(
75             env, PROMISE_INFO);
76 
77         if (options.forceFallbackAdapter) {
78             // Software adapters are not currently supported.
79             promise.Resolve({});
80             return promise;
81         }
82 
83         auto adapters = instance_.GetAdapters();
84         if (adapters.empty()) {
85             promise.Resolve({});
86             return promise;
87         }
88 
89 #if defined(_WIN32)
90         constexpr auto defaultBackendType = wgpu::BackendType::D3D12;
91 #elif defined(__linux__)
92         constexpr auto defaultBackendType = wgpu::BackendType::Vulkan;
93 #elif defined(__APPLE__)
94         constexpr auto defaultBackendType = wgpu::BackendType::Metal;
95 #else
96 #    error "Unsupported platform"
97 #endif
98 
99         auto targetBackendType = defaultBackendType;
100         std::string forceBackend;
101 
102         // Check for override from env var
103         if (std::string envVar = GetEnvVar("DAWNNODE_BACKEND"); !envVar.empty()) {
104             forceBackend = envVar;
105         }
106 
107         // Check for override from flag
108         if (auto f = flags_.Get("dawn-backend")) {
109             forceBackend = *f;
110         }
111 
112         std::transform(forceBackend.begin(), forceBackend.end(), forceBackend.begin(),
113                        [](char c) { return std::tolower(c); });
114 
115         if (!forceBackend.empty()) {
116             if (forceBackend == "null") {
117                 targetBackendType = wgpu::BackendType::Null;
118             } else if (forceBackend == "webgpu") {
119                 targetBackendType = wgpu::BackendType::WebGPU;
120             } else if (forceBackend == "d3d11") {
121                 targetBackendType = wgpu::BackendType::D3D11;
122             } else if (forceBackend == "d3d12" || forceBackend == "d3d") {
123                 targetBackendType = wgpu::BackendType::D3D12;
124             } else if (forceBackend == "metal") {
125                 targetBackendType = wgpu::BackendType::Metal;
126             } else if (forceBackend == "vulkan" || forceBackend == "vk") {
127                 targetBackendType = wgpu::BackendType::Vulkan;
128             } else if (forceBackend == "opengl" || forceBackend == "gl") {
129                 targetBackendType = wgpu::BackendType::OpenGL;
130             } else if (forceBackend == "opengles" || forceBackend == "gles") {
131                 targetBackendType = wgpu::BackendType::OpenGLES;
132             }
133         }
134 
135         // Default to first adapter if we don't find a match
136         size_t adapterIndex = 0;
137         for (size_t i = 0; i < adapters.size(); ++i) {
138             wgpu::AdapterProperties props;
139             adapters[i].GetProperties(&props);
140             if (props.backendType == targetBackendType) {
141                 adapterIndex = i;
142                 break;
143             }
144         }
145 
146         auto adapter = GPUAdapter::Create<GPUAdapter>(env, adapters[adapterIndex], flags_);
147         promise.Resolve(std::optional<interop::Interface<interop::GPUAdapter>>(adapter));
148         return promise;
149     }
150 
151 }}  // namespace wgpu::binding
152