blob: 666ea6cfb6c0ec762f06d687b399c45f21d77dfe [file] [log] [blame]
/*
* Copyright 2019 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "dawn/dawncpp.h"
#include "dawn_native/DawnNative.h"
#include "tools/gpu/dawn/DawnTestContext.h"
#ifdef SK_BUILD_FOR_UNIX
#include "GL/glx.h"
#endif
#ifdef SK_BUILD_FOR_WIN
#include <windows.h>
#endif
#define USE_OPENGL_BACKEND 0
#ifdef SK_DAWN
#include "dawn/dawn.h"
#include "dawn/dawn_proc.h"
#include "include/gpu/GrContext.h"
#include "tools/AutoreleasePool.h"
#if USE_OPENGL_BACKEND
#include "dawn_native/OpenGLBackend.h"
#endif
#if defined(SK_BUILD_FOR_MAC) && USE_OPENGL_BACKEND
#include <dlfcn.h>
static void* getProcAddressMacOS(const char* procName) {
return dlsym(RTLD_DEFAULT, procName);
}
#endif
namespace {
#ifdef SK_BUILD_FOR_WIN
class ProcGetter {
public:
typedef void(*Proc)();
ProcGetter()
: fModule(LoadLibraryA("opengl32.dll")) {
SkASSERT(!fInstance);
fInstance = this;
}
~ProcGetter() {
if (fModule) {
FreeLibrary(fModule);
}
fInstance = nullptr;
}
static void* getProcAddress(const char* name) {
return fInstance->getProc(name);
}
private:
Proc getProc(const char* name) {
PROC proc;
if (proc = GetProcAddress(fModule, name)) {
return (Proc) proc;
}
if (proc = wglGetProcAddress(name)) {
return (Proc) proc;
}
return nullptr;
}
HMODULE fModule;
static ProcGetter* fInstance;
};
ProcGetter* ProcGetter::fInstance;
#endif
class DawnFence {
public:
DawnFence(const dawn::Device& device, const dawn::Buffer& buffer)
: fDevice(device), fBuffer(buffer), fCalled(false) {
fBuffer.MapReadAsync(callback, this);
}
bool wait() {
while (!fCalled) {
fDevice.Tick();
}
return true;
}
~DawnFence() {
}
static void callback(DawnBufferMapAsyncStatus status, const void* data, uint64_t dataLength,
void* userData) {
DawnFence* fence = static_cast<DawnFence*>(userData);
fence->fCalled = true;
}
dawn::Buffer buffer() { return fBuffer; }
private:
dawn::Device fDevice;
dawn::Buffer fBuffer;
bool fCalled;
};
/**
* Implements sk_gpu_test::FenceSync for Dawn.
*/
class DawnFenceSync : public sk_gpu_test::FenceSync {
public:
DawnFenceSync(dawn::Device device) : fDevice(device) {
}
~DawnFenceSync() override {
}
sk_gpu_test::PlatformFence SK_WARN_UNUSED_RESULT insertFence() const override {
dawn::Buffer buffer;
if (fBuffers.empty()) {
dawn::BufferDescriptor desc;
desc.usage = dawn::BufferUsage::MapRead | dawn::BufferUsage::CopyDst;
desc.size = 1;
buffer = fDevice.CreateBuffer(&desc);
} else {
buffer = fBuffers.back();
fBuffers.pop_back();
}
DawnFence* fence = new DawnFence(fDevice, buffer);
return reinterpret_cast<sk_gpu_test::PlatformFence>(fence);
}
bool waitFence(sk_gpu_test::PlatformFence opaqueFence) const override {
fAutoreleasePool.drain();
DawnFence* fence = reinterpret_cast<DawnFence*>(opaqueFence);
return fence->wait();
}
void deleteFence(sk_gpu_test::PlatformFence opaqueFence) const override {
DawnFence* fence = reinterpret_cast<DawnFence*>(opaqueFence);
fBuffers.push_back(fence->buffer());
delete fence;
}
private:
dawn::Device fDevice;
mutable std::vector<dawn::Buffer> fBuffers;
mutable AutoreleasePool fAutoreleasePool;
typedef sk_gpu_test::FenceSync INHERITED;
};
class DawnTestContextImpl : public sk_gpu_test::DawnTestContext {
public:
static dawn::Device createDevice(const dawn_native::Instance& instance,
dawn_native::BackendType type) {
DawnProcTable backendProcs = dawn_native::GetProcs();
dawnProcSetProcs(&backendProcs);
std::vector<dawn_native::Adapter> adapters = instance.GetAdapters();
for (dawn_native::Adapter adapter : adapters) {
if (adapter.GetBackendType() == type) {
return adapter.CreateDevice();
}
}
return nullptr;
}
static DawnTestContext* Create(DawnTestContext* sharedContext) {
std::unique_ptr<dawn_native::Instance> instance = std::make_unique<dawn_native::Instance>();
dawn::Device device;
if (sharedContext) {
device = sharedContext->getDevice();
} else {
dawn_native::BackendType type;
#if USE_OPENGL_BACKEND
dawn_native::opengl::AdapterDiscoveryOptions adapterOptions;
adapterOptions.getProc = reinterpret_cast<void*(*)(const char*)>(
#if defined(SK_BUILD_FOR_UNIX)
glXGetProcAddress
#elif defined(SK_BUILD_FOR_MAC)
getProcAddressMacOS
#elif defined(SK_BUILD_FOR_WIN)
ProcGetter::getProcAddress
#endif
);
instance->DiscoverAdapters(&adapterOptions);
type = dawn_native::BackendType::OpenGL;
#else
instance->DiscoverDefaultAdapters();
#if defined(SK_BUILD_FOR_MAC)
type = dawn_native::BackendType::Metal;
#elif defined(SK_BUILD_FOR_WIN)
type = dawn_native::BackendType::D3D12;
#elif defined(SK_BUILD_FOR_UNIX)
type = dawn_native::BackendType::Vulkan;
#endif
#endif
device = createDevice(*instance, type);
}
if (!device) {
return nullptr;
}
return new DawnTestContextImpl(std::move(instance), device);
}
~DawnTestContextImpl() override { this->teardown(); }
void testAbandon() override {}
// There is really nothing to here since we don't own any unqueued command buffers here.
void submit() override {}
void finish() override {}
sk_sp<GrContext> makeGrContext(const GrContextOptions& options) override {
return GrContext::MakeDawn(fDevice, options);
}
protected:
void teardown() override {
INHERITED::teardown();
}
private:
DawnTestContextImpl(std::unique_ptr<dawn_native::Instance> instance,
const dawn::Device& device)
: DawnTestContext(device)
, fInstance(std::move(instance)) {
fFenceSync.reset(new DawnFenceSync(fDevice));
}
void onPlatformMakeCurrent() const override {}
std::function<void()> onPlatformGetAutoContextRestore() const override { return nullptr; }
void onPlatformSwapBuffers() const override {}
std::unique_ptr<dawn_native::Instance> fInstance;
typedef sk_gpu_test::DawnTestContext INHERITED;
};
} // anonymous namespace
namespace sk_gpu_test {
DawnTestContext* CreatePlatformDawnTestContext(DawnTestContext* sharedContext) {
return DawnTestContextImpl::Create(sharedContext);
}
} // namespace sk_gpu_test
#endif