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 "dawn/dawncpp.h"
9 #include "dawn_native/DawnNative.h"
10 #include "tools/gpu/dawn/DawnTestContext.h"
11
12 #ifdef SK_BUILD_FOR_UNIX
13 #include "GL/glx.h"
14 #endif
15
16 #ifdef SK_BUILD_FOR_WIN
17 #include <windows.h>
18 #endif
19
20 #define USE_OPENGL_BACKEND 0
21
22 #ifdef SK_DAWN
23 #include "dawn/dawn.h"
24 #include "include/gpu/GrContext.h"
25 #include "tools/AutoreleasePool.h"
26 #if USE_OPENGL_BACKEND
27 #include "dawn_native/OpenGLBackend.h"
28 #endif
29
30 #if defined(SK_BUILD_FOR_MAC) && USE_OPENGL_BACKEND
31 #include <dlfcn.h>
getProcAddressMacOS(const char * procName)32 static void* getProcAddressMacOS(const char* procName) {
33 return dlsym(RTLD_DEFAULT, procName);
34 }
35 #endif
36
37 namespace {
38
39 #ifdef SK_BUILD_FOR_WIN
40 class ProcGetter {
41 public:
42 typedef void(*Proc)();
43
ProcGetter()44 ProcGetter()
45 : fModule(LoadLibraryA("opengl32.dll")) {
46 SkASSERT(!fInstance);
47 fInstance = this;
48 }
49
~ProcGetter()50 ~ProcGetter() {
51 if (fModule) {
52 FreeLibrary(fModule);
53 }
54 fInstance = nullptr;
55 }
56
getProcAddress(const char * name)57 static void* getProcAddress(const char* name) {
58 return fInstance->getProc(name);
59 }
60
61 private:
getProc(const char * name)62 Proc getProc(const char* name) {
63 PROC proc;
64 if (proc = GetProcAddress(fModule, name)) {
65 return (Proc) proc;
66 }
67 if (proc = wglGetProcAddress(name)) {
68 return (Proc) proc;
69 }
70 return nullptr;
71 }
72
73 HMODULE fModule;
74 static ProcGetter* fInstance;
75 };
76
77 ProcGetter* ProcGetter::fInstance;
78 #endif
79
80 class DawnFence {
81 public:
DawnFence(const dawn::Device & device,const dawn::Buffer & buffer)82 DawnFence(const dawn::Device& device, const dawn::Buffer& buffer)
83 : fDevice(device), fBuffer(buffer), fCalled(false) {
84 fBuffer.MapReadAsync(callback, this);
85 }
86
wait()87 bool wait() {
88 while (!fCalled) {
89 fDevice.Tick();
90 }
91 return true;
92 }
93
~DawnFence()94 ~DawnFence() {
95 }
96
callback(DawnBufferMapAsyncStatus status,const void * data,uint64_t dataLength,void * userData)97 static void callback(DawnBufferMapAsyncStatus status, const void* data, uint64_t dataLength,
98 void* userData) {
99 DawnFence* fence = static_cast<DawnFence*>(userData);
100 fence->fCalled = true;
101 }
buffer()102 dawn::Buffer buffer() { return fBuffer; }
103
104 private:
105 dawn::Device fDevice;
106 dawn::Buffer fBuffer;
107 bool fCalled;
108 };
109
110 /**
111 * Implements sk_gpu_test::FenceSync for Dawn.
112 */
113 class DawnFenceSync : public sk_gpu_test::FenceSync {
114 public:
DawnFenceSync(dawn::Device device)115 DawnFenceSync(dawn::Device device) : fDevice(device) {
116 }
117
~DawnFenceSync()118 ~DawnFenceSync() override {
119 }
120
insertFence() const121 sk_gpu_test::PlatformFence SK_WARN_UNUSED_RESULT insertFence() const override {
122 dawn::Buffer buffer;
123 if (fBuffers.empty()) {
124 dawn::BufferDescriptor desc;
125 desc.usage = dawn::BufferUsageBit::MapRead | dawn::BufferUsageBit::CopyDst;
126 desc.size = 1;
127 buffer = fDevice.CreateBuffer(&desc);
128 } else {
129 buffer = fBuffers.back();
130 fBuffers.pop_back();
131 }
132 DawnFence* fence = new DawnFence(fDevice, buffer);
133 return reinterpret_cast<sk_gpu_test::PlatformFence>(fence);
134 }
135
waitFence(sk_gpu_test::PlatformFence opaqueFence) const136 bool waitFence(sk_gpu_test::PlatformFence opaqueFence) const override {
137 fAutoreleasePool.drain();
138 DawnFence* fence = reinterpret_cast<DawnFence*>(opaqueFence);
139 return fence->wait();
140 }
141
deleteFence(sk_gpu_test::PlatformFence opaqueFence) const142 void deleteFence(sk_gpu_test::PlatformFence opaqueFence) const override {
143 DawnFence* fence = reinterpret_cast<DawnFence*>(opaqueFence);
144 fBuffers.push_back(fence->buffer());
145 delete fence;
146 }
147
148 private:
149 dawn::Device fDevice;
150 mutable std::vector<dawn::Buffer> fBuffers;
151 mutable AutoreleasePool fAutoreleasePool;
152 typedef sk_gpu_test::FenceSync INHERITED;
153 };
154
155 class DawnTestContextImpl : public sk_gpu_test::DawnTestContext {
156 public:
createDevice(const dawn_native::Instance & instance,dawn_native::BackendType type)157 static dawn::Device createDevice(const dawn_native::Instance& instance,
158 dawn_native::BackendType type) {
159 DawnProcTable backendProcs = dawn_native::GetProcs();
160 dawnSetProcs(&backendProcs);
161
162 std::vector<dawn_native::Adapter> adapters = instance.GetAdapters();
163 for (dawn_native::Adapter adapter : adapters) {
164 if (adapter.GetBackendType() == type) {
165 return adapter.CreateDevice();
166 }
167 }
168 return nullptr;
169 }
170
Create(DawnTestContext * sharedContext)171 static DawnTestContext* Create(DawnTestContext* sharedContext) {
172 std::unique_ptr<dawn_native::Instance> instance = std::make_unique<dawn_native::Instance>();
173 dawn::Device device;
174 if (sharedContext) {
175 device = sharedContext->getDevice();
176 } else {
177 dawn_native::BackendType type;
178 #if USE_OPENGL_BACKEND
179 dawn_native::opengl::AdapterDiscoveryOptions adapterOptions;
180 adapterOptions.getProc = reinterpret_cast<void*(*)(const char*)>(
181 #if defined(SK_BUILD_FOR_UNIX)
182 glXGetProcAddress
183 #elif defined(SK_BUILD_FOR_MAC)
184 getProcAddressMacOS
185 #elif defined(SK_BUILD_FOR_WIN)
186 ProcGetter::getProcAddress
187 #endif
188 );
189 instance->DiscoverAdapters(&adapterOptions);
190 type = dawn_native::BackendType::OpenGL;
191 #else
192 instance->DiscoverDefaultAdapters();
193 #if defined(SK_BUILD_FOR_MAC)
194 type = dawn_native::BackendType::Metal;
195 #elif defined(SK_BUILD_FOR_WIN)
196 type = dawn_native::BackendType::D3D12;
197 #elif defined(SK_BUILD_FOR_UNIX)
198 type = dawn_native::BackendType::Vulkan;
199 #endif
200 #endif
201 device = createDevice(*instance, type);
202 }
203 if (!device) {
204 return nullptr;
205 }
206 return new DawnTestContextImpl(std::move(instance), device);
207 }
208
~DawnTestContextImpl()209 ~DawnTestContextImpl() override { this->teardown(); }
210
testAbandon()211 void testAbandon() override {}
212
213 // There is really nothing to here since we don't own any unqueued command buffers here.
submit()214 void submit() override {}
215
finish()216 void finish() override {}
217
makeGrContext(const GrContextOptions & options)218 sk_sp<GrContext> makeGrContext(const GrContextOptions& options) override {
219 return GrContext::MakeDawn(fDevice, options);
220 }
221
222 protected:
teardown()223 void teardown() override {
224 INHERITED::teardown();
225 }
226
227 private:
DawnTestContextImpl(std::unique_ptr<dawn_native::Instance> instance,const dawn::Device & device)228 DawnTestContextImpl(std::unique_ptr<dawn_native::Instance> instance,
229 const dawn::Device& device)
230 : DawnTestContext(device)
231 , fInstance(std::move(instance)) {
232 fFenceSync.reset(new DawnFenceSync(fDevice));
233 }
234
onPlatformMakeCurrent() const235 void onPlatformMakeCurrent() const override {}
onPlatformGetAutoContextRestore() const236 std::function<void()> onPlatformGetAutoContextRestore() const override { return nullptr; }
onPlatformSwapBuffers() const237 void onPlatformSwapBuffers() const override {}
238 std::unique_ptr<dawn_native::Instance> fInstance;
239
240 typedef sk_gpu_test::DawnTestContext INHERITED;
241 };
242 } // anonymous namespace
243
244 namespace sk_gpu_test {
CreatePlatformDawnTestContext(DawnTestContext * sharedContext)245 DawnTestContext* CreatePlatformDawnTestContext(DawnTestContext* sharedContext) {
246 return DawnTestContextImpl::Create(sharedContext);
247 }
248 } // namespace sk_gpu_test
249
250 #endif
251