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/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 "dawn/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#endif
29
30#if defined(SK_BUILD_FOR_MAC) && USE_OPENGL_BACKEND
31#include <dlfcn.h>
32static void* getProcAddressMacOS(const char* procName) {
33    return dlsym(RTLD_DEFAULT, procName);
34}
35#endif
36
37namespace {
38
39#ifdef SK_BUILD_FOR_WIN
40class ProcGetter {
41public:
42    typedef void(*Proc)();
43
44    ProcGetter()
45      : fModule(LoadLibraryA("opengl32.dll")) {
46        SkASSERT(!fInstance);
47        fInstance = this;
48    }
49
50    ~ProcGetter() {
51        if (fModule) {
52            FreeLibrary(fModule);
53        }
54        fInstance = nullptr;
55    }
56
57    static void* getProcAddress(const char* name) {
58        return fInstance->getProc(name);
59    }
60
61private:
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
77ProcGetter* ProcGetter::fInstance;
78#endif
79
80static void PrintDeviceError(WGPUErrorType, const char* message, void*) {
81    SkDebugf("Device error: %s\n", message);
82}
83
84class DawnTestContextImpl : public sk_gpu_test::DawnTestContext {
85public:
86    static wgpu::Device createDevice(const dawn_native::Instance& instance,
87                                     dawn_native::BackendType type) {
88        DawnProcTable backendProcs = dawn_native::GetProcs();
89        dawnProcSetProcs(&backendProcs);
90
91        std::vector<dawn_native::Adapter> adapters = instance.GetAdapters();
92        for (dawn_native::Adapter adapter : adapters) {
93            if (adapter.GetBackendType() == type) {
94                return wgpu::Device::Acquire(adapter.CreateDevice());
95            }
96        }
97        return nullptr;
98    }
99
100    static DawnTestContext* Create(DawnTestContext* sharedContext) {
101        std::unique_ptr<dawn_native::Instance> instance = std::make_unique<dawn_native::Instance>();
102        wgpu::Device device;
103        if (sharedContext) {
104            device = sharedContext->getDevice();
105        } else {
106            dawn_native::BackendType type;
107#if USE_OPENGL_BACKEND
108            dawn_native::opengl::AdapterDiscoveryOptions adapterOptions;
109            adapterOptions.getProc = reinterpret_cast<void*(*)(const char*)>(
110#if defined(SK_BUILD_FOR_UNIX)
111                glXGetProcAddress
112#elif defined(SK_BUILD_FOR_MAC)
113                getProcAddressMacOS
114#elif defined(SK_BUILD_FOR_WIN)
115                ProcGetter::getProcAddress
116#endif
117            );
118            instance->DiscoverAdapters(&adapterOptions);
119            type = dawn_native::BackendType::OpenGL;
120#else
121            instance->DiscoverDefaultAdapters();
122#if defined(SK_BUILD_FOR_MAC)
123            type = dawn_native::BackendType::Metal;
124#elif defined(SK_BUILD_FOR_WIN)
125            type = dawn_native::BackendType::D3D12;
126#elif defined(SK_BUILD_FOR_UNIX)
127            type = dawn_native::BackendType::Vulkan;
128#endif
129#endif
130            device = createDevice(*instance, type);
131            device.SetUncapturedErrorCallback(PrintDeviceError, 0);
132        }
133        if (!device) {
134            return nullptr;
135        }
136        return new DawnTestContextImpl(std::move(instance), device);
137    }
138
139    ~DawnTestContextImpl() override { this->teardown(); }
140
141    void testAbandon() override {}
142
143    void finish() override {}
144
145    sk_sp<GrDirectContext> makeContext(const GrContextOptions& options) override {
146        return GrDirectContext::MakeDawn(fDevice, options);
147    }
148
149protected:
150    void teardown() override {
151        INHERITED::teardown();
152    }
153
154private:
155    DawnTestContextImpl(std::unique_ptr<dawn_native::Instance> instance,
156                        const wgpu::Device& device)
157            : DawnTestContext(std::move(instance), device) {
158        fFenceSupport = true;
159    }
160
161    void onPlatformMakeNotCurrent() const override {}
162    void onPlatformMakeCurrent() const override {}
163    std::function<void()> onPlatformGetAutoContextRestore() const override  { return nullptr; }
164
165    using INHERITED = sk_gpu_test::DawnTestContext;
166};
167}  // anonymous namespace
168
169namespace sk_gpu_test {
170DawnTestContext* CreatePlatformDawnTestContext(DawnTestContext* sharedContext) {
171    return DawnTestContextImpl::Create(sharedContext);
172}
173}  // namespace sk_gpu_test
174
175#endif
176