1 /*
2 * Copyright 2019 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "webgpu/webgpu_cpp.h"
9 #include "tools/gpu/dawn/DawnTestContext.h"
10
11 #ifdef SK_BUILD_FOR_UNIX
12 #include "GL/glx.h"
13 #endif
14
15 #ifdef SK_BUILD_FOR_WIN
16 #include <windows.h>
17 #endif
18
19 #define USE_OPENGL_BACKEND 0
20
21 #ifdef SK_DAWN
22 #include "webgpu/webgpu.h"
23 #include "dawn/dawn_proc.h"
24 #include "include/gpu/GrDirectContext.h"
25 #include "tools/AutoreleasePool.h"
26 #if USE_OPENGL_BACKEND
27 #include "dawn/native/OpenGLBackend.h"
28 #elif defined(SK_BUILD_FOR_MAC)
29 #include "dawn/native/MetalBackend.h"
30 #elif defined(SK_BUILD_FOR_WIN)
31 #include "dawn/native/D3D12Backend.h"
32 #elif defined(SK_BUILD_FOR_UNIX) || (defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26)
33 #include "dawn/native/VulkanBackend.h"
34 #endif
35
36 #if defined(SK_BUILD_FOR_MAC) && USE_OPENGL_BACKEND
37 #include <dlfcn.h>
getProcAddressMacOS(const char * procName)38 static void* getProcAddressMacOS(const char* procName) {
39 return dlsym(RTLD_DEFAULT, procName);
40 }
41 #endif
42
43 namespace {
44
45 #ifdef SK_BUILD_FOR_WIN
46 class ProcGetter {
47 public:
48 typedef void(*Proc)();
49
ProcGetter()50 ProcGetter()
51 : fModule(LoadLibraryA("opengl32.dll")) {
52 SkASSERT(!fInstance);
53 fInstance = this;
54 }
55
~ProcGetter()56 ~ProcGetter() {
57 if (fModule) {
58 FreeLibrary(fModule);
59 }
60 fInstance = nullptr;
61 }
62
getProcAddress(const char * name)63 static void* getProcAddress(const char* name) {
64 return fInstance->getProc(name);
65 }
66
67 private:
getProc(const char * name)68 Proc getProc(const char* name) {
69 PROC proc;
70 if ((proc = GetProcAddress(fModule, name))) {
71 return (Proc) proc;
72 }
73 if ((proc = wglGetProcAddress(name))) {
74 return (Proc) proc;
75 }
76 return nullptr;
77 }
78
79 HMODULE fModule;
80 static ProcGetter* fInstance;
81 };
82
83 ProcGetter* ProcGetter::fInstance;
84 #endif
85
PrintDeviceError(WGPUErrorType,const char * message,void *)86 static void PrintDeviceError(WGPUErrorType, const char* message, void*) {
87 SkDebugf("Device error: %s\n", message);
88 }
89
PrintDeviceLostMessage(WGPUDeviceLostReason reason,const char * message,void *)90 static void PrintDeviceLostMessage(WGPUDeviceLostReason reason, const char* message, void*) {
91 if (reason != WGPUDeviceLostReason_Destroyed) {
92 SkDebugf("Device lost: %s\n", message);
93 }
94 }
95
96 class DawnTestContextImpl : public sk_gpu_test::DawnTestContext {
97 public:
createDevice(const dawn::native::Instance & instance,wgpu::BackendType type)98 static wgpu::Device createDevice(const dawn::native::Instance& instance,
99 wgpu::BackendType type) {
100 DawnProcTable backendProcs = dawn::native::GetProcs();
101 dawnProcSetProcs(&backendProcs);
102
103 std::vector<dawn::native::Adapter> adapters = instance.GetAdapters();
104 for (dawn::native::Adapter adapter : adapters) {
105 wgpu::AdapterProperties properties;
106 adapter.GetProperties(&properties);
107 if (properties.backendType == type) {
108 return wgpu::Device::Acquire(adapter.CreateDevice());
109 }
110 }
111 return nullptr;
112 }
113
Create(DawnTestContext * sharedContext)114 static DawnTestContext* Create(DawnTestContext* sharedContext) {
115 std::unique_ptr<dawn::native::Instance> instance = std::make_unique<dawn::native::Instance>();
116 wgpu::Device device;
117 if (sharedContext) {
118 device = sharedContext->getDevice();
119 } else {
120 wgpu::BackendType type;
121 #if USE_OPENGL_BACKEND
122 type = wgpu::BackendType::OpenGL;
123 dawn::native::opengl::AdapterDiscoveryOptions adapterOptions(
124 static_cast<WGPUBackendType>(type));
125 adapterOptions.getProc = reinterpret_cast<void*(*)(const char*)>(
126 #if defined(SK_BUILD_FOR_UNIX)
127 glXGetProcAddress
128 #elif defined(SK_BUILD_FOR_MAC)
129 getProcAddressMacOS
130 #elif defined(SK_BUILD_FOR_WIN)
131 ProcGetter::getProcAddress
132 #endif
133 );
134 #else // !USE_OPENGL_BACKEND
135 #if defined(SK_BUILD_FOR_MAC)
136 type = wgpu::BackendType::Metal;
137 dawn::native::metal::AdapterDiscoveryOptions adapterOptions;
138 #elif defined(SK_BUILD_FOR_WIN)
139 type = wgpu::BackendType::D3D12;
140 dawn::native::d3d12::AdapterDiscoveryOptions adapterOptions;
141 #elif defined(SK_BUILD_FOR_UNIX) || (defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26)
142 type = wgpu::BackendType::Vulkan;
143 dawn::native::vulkan::AdapterDiscoveryOptions adapterOptions;
144 #endif
145 #endif // USE_OPENGL_BACKEND
146 instance->DiscoverAdapters(&adapterOptions);
147 device = createDevice(*instance, type);
148 if (device) {
149 device.SetUncapturedErrorCallback(PrintDeviceError, 0);
150 device.SetDeviceLostCallback(PrintDeviceLostMessage, 0);
151 }
152 }
153 if (!device) {
154 return nullptr;
155 }
156 return new DawnTestContextImpl(std::move(instance), device);
157 }
158
~DawnTestContextImpl()159 ~DawnTestContextImpl() override { this->teardown(); }
160
testAbandon()161 void testAbandon() override {}
162
finish()163 void finish() override {}
164
makeContext(const GrContextOptions & options)165 sk_sp<GrDirectContext> makeContext(const GrContextOptions& options) override {
166 return GrDirectContext::MakeDawn(fDevice, options);
167 }
168
169 protected:
teardown()170 void teardown() override {
171 INHERITED::teardown();
172 }
173
174 private:
DawnTestContextImpl(std::unique_ptr<dawn::native::Instance> instance,const wgpu::Device & device)175 DawnTestContextImpl(std::unique_ptr<dawn::native::Instance> instance,
176 const wgpu::Device& device)
177 : DawnTestContext(std::move(instance), device) {
178 fFenceSupport = true;
179 }
180
onPlatformMakeNotCurrent() const181 void onPlatformMakeNotCurrent() const override {}
onPlatformMakeCurrent() const182 void onPlatformMakeCurrent() const override {}
onPlatformGetAutoContextRestore() const183 std::function<void()> onPlatformGetAutoContextRestore() const override { return nullptr; }
184
185 using INHERITED = sk_gpu_test::DawnTestContext;
186 };
187 } // anonymous namespace
188
189 namespace sk_gpu_test {
CreatePlatformDawnTestContext(DawnTestContext * sharedContext)190 DawnTestContext* CreatePlatformDawnTestContext(DawnTestContext* sharedContext) {
191 return DawnTestContextImpl::Create(sharedContext);
192 }
193 } // namespace sk_gpu_test
194
195 #endif
196