• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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