GL: implement EGL context creation in Dawn native.

An abstract base class (Device::Context) is used to avoid adding dependencies to Device, with ContextEGL derived from it. This also
leaves open the possibility of supporting other native GL contexts
in the future (e.g., glX). One temporary EGLContext is created by opengl::Backend during Adapter discovery, then one is created for and
owned by each Device.

Contexts for the desktop GL backend are also managed via EGL, which
works for most modern drivers. This also means that GLFW is now
always used in GLFW_NO_API mode.

Since contexts are now per-device, all of the default GL state
setting and debug output setup was moved from Adapter to Device.

Bug: dawn:810
Change-Id: Idfe30939f155d026fcad549787fc167cc43aa3cb
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/93981
Commit-Queue: Stephen White <senorblanco@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
Stephen White 2022-06-29 15:29:41 +00:00 committed by Dawn LUCI CQ
parent 3a2a279714
commit 9434949241
26 changed files with 438 additions and 333 deletions

View File

@ -174,6 +174,7 @@ set_if_not_defined(DAWN_THIRD_PARTY_DIR "${Dawn_SOURCE_DIR}/third_party" "Direct
set_if_not_defined(DAWN_ABSEIL_DIR "${DAWN_THIRD_PARTY_DIR}/abseil-cpp" "Directory in which to find Abseil")
set_if_not_defined(DAWN_GLFW_DIR "${DAWN_THIRD_PARTY_DIR}/glfw" "Directory in which to find GLFW")
set_if_not_defined(DAWN_JINJA2_DIR "${DAWN_THIRD_PARTY_DIR}/jinja2" "Directory in which to find Jinja2")
set_if_not_defined(DAWN_KHRONOS_DIR "${DAWN_THIRD_PARTY_DIR}/khronos" "Directory in which to find Khronos GL headers")
set_if_not_defined(DAWN_SPIRV_HEADERS_DIR "${DAWN_THIRD_PARTY_DIR}/vulkan-deps/spirv-headers/src" "Directory in which to find SPIRV-Headers")
set_if_not_defined(DAWN_SPIRV_TOOLS_DIR "${DAWN_THIRD_PARTY_DIR}/vulkan-deps/spirv-tools/src" "Directory in which to find SPIRV-Tools")
set_if_not_defined(DAWN_SWIFTSHADER_DIR "${DAWN_THIRD_PARTY_DIR}/swiftshader" "Directory in which to find swiftshader")

View File

@ -23,15 +23,14 @@ typedef void* EGLImage;
namespace dawn::native::opengl {
struct DAWN_NATIVE_EXPORT AdapterDiscoveryOptions : public AdapterDiscoveryOptionsBase {
AdapterDiscoveryOptions();
explicit AdapterDiscoveryOptions(WGPUBackendType type);
void* (*getProc)(const char*);
};
struct DAWN_NATIVE_EXPORT AdapterDiscoveryOptionsES : public AdapterDiscoveryOptionsBase {
// TODO(crbug.com/dawn/810): This struct can be removed once Chrome is no longer using it.
struct DAWN_NATIVE_EXPORT AdapterDiscoveryOptionsES : public AdapterDiscoveryOptions {
AdapterDiscoveryOptionsES();
void* (*getProc)(const char*);
};
using PresentCallback = void (*)(void*);

View File

@ -540,8 +540,12 @@ source_set("sources") {
"opengl/CommandBufferGL.h",
"opengl/ComputePipelineGL.cpp",
"opengl/ComputePipelineGL.h",
"opengl/ContextEGL.cpp",
"opengl/ContextEGL.h",
"opengl/DeviceGL.cpp",
"opengl/DeviceGL.h",
"opengl/EGLFunctions.cpp",
"opengl/EGLFunctions.h",
"opengl/Forward.h",
"opengl/GLFormat.cpp",
"opengl/GLFormat.h",
@ -575,6 +579,7 @@ source_set("sources") {
"opengl/UtilsGL.h",
"opengl/opengl_platform.h",
]
include_dirs = [ "//third_party/khronos" ]
}
if (dawn_enable_vulkan) {

View File

@ -418,8 +418,12 @@ if (DAWN_ENABLE_OPENGL)
"opengl/CommandBufferGL.h"
"opengl/ComputePipelineGL.cpp"
"opengl/ComputePipelineGL.h"
"opengl/ContextEGL.cpp"
"opengl/ContextEGL.h"
"opengl/DeviceGL.cpp"
"opengl/DeviceGL.h"
"opengl/EGLFunctions.cpp"
"opengl/EGLFunctions.h"
"opengl/Forward.h"
"opengl/GLFormat.cpp"
"opengl/GLFormat.h"
@ -454,6 +458,7 @@ if (DAWN_ENABLE_OPENGL)
"opengl/opengl_platform.h"
)
target_include_directories(dawn_native PRIVATE ${DAWN_KHRONOS_DIR})
target_link_libraries(dawn_native PRIVATE dawn_khronos_platform)
endif()

View File

@ -14,11 +14,13 @@
#include "dawn/native/opengl/AdapterGL.h"
#include <memory>
#include <string>
#include <utility>
#include "dawn/common/GPUInfo.h"
#include "dawn/common/Log.h"
#include "dawn/native/Instance.h"
#include "dawn/native/opengl/ContextEGL.h"
#include "dawn/native/opengl/DeviceGL.h"
namespace dawn::native::opengl {
@ -49,69 +51,6 @@ uint32_t GetVendorIdFromVendors(const char* vendor) {
return vendorId;
}
void KHRONOS_APIENTRY OnGLDebugMessage(GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei length,
const GLchar* message,
const void* userParam) {
const char* sourceText;
switch (source) {
case GL_DEBUG_SOURCE_API:
sourceText = "OpenGL";
break;
case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
sourceText = "Window System";
break;
case GL_DEBUG_SOURCE_SHADER_COMPILER:
sourceText = "Shader Compiler";
break;
case GL_DEBUG_SOURCE_THIRD_PARTY:
sourceText = "Third Party";
break;
case GL_DEBUG_SOURCE_APPLICATION:
sourceText = "Application";
break;
case GL_DEBUG_SOURCE_OTHER:
sourceText = "Other";
break;
default:
sourceText = "UNKNOWN";
break;
}
const char* severityText;
switch (severity) {
case GL_DEBUG_SEVERITY_HIGH:
severityText = "High";
break;
case GL_DEBUG_SEVERITY_MEDIUM:
severityText = "Medium";
break;
case GL_DEBUG_SEVERITY_LOW:
severityText = "Low";
break;
case GL_DEBUG_SEVERITY_NOTIFICATION:
severityText = "Notification";
break;
default:
severityText = "UNKNOWN";
break;
}
if (type == GL_DEBUG_TYPE_ERROR) {
dawn::WarningLog() << "OpenGL error:"
<< "\n Source: " << sourceText //
<< "\n ID: " << id //
<< "\n Severity: " << severityText //
<< "\n Message: " << message;
// Abort on an error when in Debug mode.
UNREACHABLE();
}
}
} // anonymous namespace
Adapter::Adapter(InstanceBase* instance, wgpu::BackendType backendType)
@ -119,6 +58,7 @@ Adapter::Adapter(InstanceBase* instance, wgpu::BackendType backendType)
MaybeError Adapter::InitializeGLFunctions(void* (*getProc)(const char*)) {
// Use getProc to populate the dispatch table
mEGLFunctions.Init(getProc);
return mFunctions.Initialize(getProc);
}
@ -134,47 +74,6 @@ MaybeError Adapter::InitializeImpl() {
ASSERT(GetBackendType() == wgpu::BackendType::OpenGL);
}
// Use the debug output functionality to get notified about GL errors
// TODO(cwallez@chromium.org): add support for the KHR_debug and ARB_debug_output
// extensions
bool hasDebugOutput = mFunctions.IsAtLeastGL(4, 3) || mFunctions.IsAtLeastGLES(3, 2);
if (GetInstance()->IsBackendValidationEnabled() && hasDebugOutput) {
mFunctions.Enable(GL_DEBUG_OUTPUT);
mFunctions.Enable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
// Any GL error; dangerous undefined behavior; any shader compiler and linker errors
mFunctions.DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH, 0,
nullptr, GL_TRUE);
// Severe performance warnings; GLSL or other shader compiler and linker warnings;
// use of currently deprecated behavior
mFunctions.DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM, 0,
nullptr, GL_TRUE);
// Performance warnings from redundant state changes; trivial undefined behavior
// This is disabled because we do an incredible amount of redundant state changes.
mFunctions.DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW, 0,
nullptr, GL_FALSE);
// Any message which is not an error or performance concern
mFunctions.DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION,
0, nullptr, GL_FALSE);
mFunctions.DebugMessageCallback(&OnGLDebugMessage, nullptr);
}
// Set state that never changes between devices.
mFunctions.Enable(GL_DEPTH_TEST);
mFunctions.Enable(GL_SCISSOR_TEST);
mFunctions.Enable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
if (mFunctions.GetVersion().IsDesktop()) {
// These are not necessary on GLES. The functionality is enabled by default, and
// works by specifying sample counts and SRGB textures, respectively.
mFunctions.Enable(GL_MULTISAMPLE);
mFunctions.Enable(GL_FRAMEBUFFER_SRGB);
}
mFunctions.Enable(GL_SAMPLE_MASK);
mName = reinterpret_cast<const char*>(mFunctions.GetString(GL_RENDERER));
// Workaroud to find vendor id from vendor name
@ -251,9 +150,12 @@ MaybeError Adapter::InitializeSupportedLimitsImpl(CombinedLimits* limits) {
}
ResultOrError<Ref<DeviceBase>> Adapter::CreateDeviceImpl(const DeviceDescriptor* descriptor) {
// There is no limit on the number of devices created from this adapter because they can
// all share the same backing OpenGL context.
return Device::Create(this, descriptor, mFunctions);
EGLenum api =
GetBackendType() == wgpu::BackendType::OpenGL ? EGL_OPENGL_API : EGL_OPENGL_ES_API;
std::unique_ptr<Device::Context> context = ContextEGL::Create(mEGLFunctions, api);
return Device::Create(this, descriptor, mFunctions, std::move(context));
}
} // namespace dawn::native::opengl

View File

@ -16,6 +16,7 @@
#define SRC_DAWN_NATIVE_OPENGL_ADAPTERGL_H_
#include "dawn/native/Adapter.h"
#include "dawn/native/opengl/EGLFunctions.h"
#include "dawn/native/opengl/OpenGLFunctions.h"
namespace dawn::native::opengl {
@ -38,6 +39,7 @@ class Adapter : public AdapterBase {
ResultOrError<Ref<DeviceBase>> CreateDeviceImpl(const DeviceDescriptor* descriptor) override;
OpenGLFunctions mFunctions;
EGLFunctions mEGLFunctions;
};
} // namespace dawn::native::opengl

View File

@ -14,10 +14,17 @@
#include "dawn/native/opengl/BackendGL.h"
#include <EGL/egl.h>
#include <memory>
#include <utility>
#include "dawn/common/SystemUtils.h"
#include "dawn/native/Instance.h"
#include "dawn/native/OpenGLBackend.h"
#include "dawn/native/opengl/AdapterGL.h"
#include "dawn/native/opengl/ContextEGL.h"
#include "dawn/native/opengl/EGLFunctions.h"
namespace dawn::native::opengl {
@ -27,8 +34,53 @@ Backend::Backend(InstanceBase* instance, wgpu::BackendType backendType)
: BackendConnection(instance, backendType) {}
std::vector<Ref<AdapterBase>> Backend::DiscoverDefaultAdapters() {
// The OpenGL backend needs at least "getProcAddress" to discover an adapter.
std::vector<Ref<AdapterBase>> adapters;
#if DAWN_PLATFORM_IS(WINDOWS)
const char* eglLib = "libEGL.dll";
#elif DAWN_PLATFORM_IS(MACOS)
const char* eglLib = "libEGL.dylib";
#else
const char* eglLib = "libEGL.so";
#endif
if (!mLibEGL.Valid() && !mLibEGL.Open(eglLib)) {
return {};
}
AdapterDiscoveryOptions options(ToAPI(GetType()));
options.getProc =
reinterpret_cast<void* (*)(const char*)>(mLibEGL.GetProc("eglGetProcAddress"));
if (!options.getProc) {
return {};
}
EGLFunctions egl;
egl.Init(options.getProc);
EGLenum api = GetType() == wgpu::BackendType::OpenGLES ? EGL_OPENGL_ES_API : EGL_OPENGL_API;
std::unique_ptr<Device::Context> context = ContextEGL::Create(egl, api);
if (!context) {
return {};
}
EGLDisplay prevDisplay = egl.GetCurrentDisplay();
EGLContext prevDrawSurface = egl.GetCurrentSurface(EGL_DRAW);
EGLContext prevReadSurface = egl.GetCurrentSurface(EGL_READ);
EGLContext prevContext = egl.GetCurrentContext();
context->MakeCurrent();
auto result = DiscoverAdapters(&options);
if (result.IsError()) {
GetInstance()->ConsumedError(result.AcquireError());
} else {
auto value = result.AcquireSuccess();
adapters.insert(adapters.end(), value.begin(), value.end());
}
egl.MakeCurrent(prevDisplay, prevDrawSurface, prevReadSurface, prevContext);
return adapters;
}
ResultOrError<std::vector<Ref<AdapterBase>>> Backend::DiscoverAdapters(

View File

@ -17,6 +17,7 @@
#include <vector>
#include "dawn/common/DynamicLib.h"
#include "dawn/native/BackendConnection.h"
namespace dawn::native::opengl {
@ -31,6 +32,7 @@ class Backend : public BackendConnection {
private:
bool mCreatedAdapter = false;
DynamicLib mLibEGL;
};
} // namespace dawn::native::opengl

View File

@ -0,0 +1,78 @@
// Copyright 2022 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn/native/opengl/ContextEGL.h"
#include <memory>
#include <vector>
namespace dawn::native::opengl {
std::unique_ptr<ContextEGL> ContextEGL::Create(const EGLFunctions& egl, EGLenum api) {
EGLDisplay display = egl.GetCurrentDisplay();
if (display == EGL_NO_DISPLAY) {
display = egl.GetDisplay(EGL_DEFAULT_DISPLAY);
}
if (display == EGL_NO_DISPLAY) {
return nullptr;
}
EGLint renderableType = api == EGL_OPENGL_ES_API ? EGL_OPENGL_ES3_BIT : EGL_OPENGL_BIT;
egl.Initialize(display, nullptr, nullptr);
// Since we're creating a surfaceless context, the only thing we really care
// about is the RENDERABLE_TYPE.
EGLint config_attribs[] = {EGL_RENDERABLE_TYPE, renderableType, EGL_NONE};
EGLint num_config;
EGLConfig config;
if (egl.ChooseConfig(display, config_attribs, &config, 1, &num_config) == EGL_FALSE) {
return nullptr;
}
if (!egl.BindAPI(api)) {
return nullptr;
}
EGLint major, minor;
if (api == EGL_OPENGL_ES_API) {
major = 3;
minor = 1;
} else {
major = 4;
minor = 4;
}
EGLint attrib_list[] = {
EGL_CONTEXT_MAJOR_VERSION, major, EGL_CONTEXT_MINOR_VERSION, minor, EGL_NONE, EGL_NONE,
};
EGLContext context = egl.CreateContext(display, config, EGL_NO_CONTEXT, attrib_list);
if (!context) {
return nullptr;
}
return std::unique_ptr<ContextEGL>(new ContextEGL(egl, display, context));
}
void ContextEGL::MakeCurrent() {
egl.MakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, mContext);
}
ContextEGL::~ContextEGL() {
egl.DestroyContext(mDisplay, mContext);
}
} // namespace dawn::native::opengl

View File

@ -0,0 +1,44 @@
// Copyright 2022 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_DAWN_NATIVE_OPENGL_CONTEXTEGL_H_
#define SRC_DAWN_NATIVE_OPENGL_CONTEXTEGL_H_
#include <EGL/egl.h>
#include <memory>
#include "dawn/native/opengl/DeviceGL.h"
#include "dawn/native/opengl/EGLFunctions.h"
namespace dawn::native::opengl {
class ContextEGL : public Device::Context {
public:
static std::unique_ptr<ContextEGL> Create(const EGLFunctions& functions, EGLenum api);
void MakeCurrent() override;
~ContextEGL() override;
private:
ContextEGL(const EGLFunctions& functions, EGLDisplay display, EGLContext context)
: egl(functions), mDisplay(display), mContext(context) {}
const EGLFunctions egl;
EGLDisplay mDisplay;
EGLContext mContext;
};
} // namespace dawn::native::opengl
#endif // SRC_DAWN_NATIVE_OPENGL_CONTEXTEGL_H_

View File

@ -14,9 +14,12 @@
#include "dawn/native/opengl/DeviceGL.h"
#include "dawn/common/Log.h"
#include "dawn/native/BackendConnection.h"
#include "dawn/native/BindGroupLayout.h"
#include "dawn/native/ErrorData.h"
#include "dawn/native/Instance.h"
#include "dawn/native/StagingBuffer.h"
#include "dawn/native/opengl/BindGroupGL.h"
#include "dawn/native/opengl/BindGroupLayoutGL.h"
@ -32,30 +35,141 @@
#include "dawn/native/opengl/SwapChainGL.h"
#include "dawn/native/opengl/TextureGL.h"
namespace {
void KHRONOS_APIENTRY OnGLDebugMessage(GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei length,
const GLchar* message,
const void* userParam) {
const char* sourceText;
switch (source) {
case GL_DEBUG_SOURCE_API:
sourceText = "OpenGL";
break;
case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
sourceText = "Window System";
break;
case GL_DEBUG_SOURCE_SHADER_COMPILER:
sourceText = "Shader Compiler";
break;
case GL_DEBUG_SOURCE_THIRD_PARTY:
sourceText = "Third Party";
break;
case GL_DEBUG_SOURCE_APPLICATION:
sourceText = "Application";
break;
case GL_DEBUG_SOURCE_OTHER:
sourceText = "Other";
break;
default:
sourceText = "UNKNOWN";
break;
}
const char* severityText;
switch (severity) {
case GL_DEBUG_SEVERITY_HIGH:
severityText = "High";
break;
case GL_DEBUG_SEVERITY_MEDIUM:
severityText = "Medium";
break;
case GL_DEBUG_SEVERITY_LOW:
severityText = "Low";
break;
case GL_DEBUG_SEVERITY_NOTIFICATION:
severityText = "Notification";
break;
default:
severityText = "UNKNOWN";
break;
}
if (type == GL_DEBUG_TYPE_ERROR) {
dawn::WarningLog() << "OpenGL error:"
<< "\n Source: " << sourceText //
<< "\n ID: " << id //
<< "\n Severity: " << severityText //
<< "\n Message: " << message;
// Abort on an error when in Debug mode.
UNREACHABLE();
}
}
} // anonymous namespace
namespace dawn::native::opengl {
// static
ResultOrError<Ref<Device>> Device::Create(AdapterBase* adapter,
const DeviceDescriptor* descriptor,
const OpenGLFunctions& functions) {
Ref<Device> device = AcquireRef(new Device(adapter, descriptor, functions));
const OpenGLFunctions& functions,
std::unique_ptr<Context> context) {
Ref<Device> device = AcquireRef(new Device(adapter, descriptor, functions, std::move(context)));
DAWN_TRY(device->Initialize(descriptor));
return device;
}
Device::Device(AdapterBase* adapter,
const DeviceDescriptor* descriptor,
const OpenGLFunctions& functions)
: DeviceBase(adapter, descriptor), mGL(functions) {}
const OpenGLFunctions& functions,
std::unique_ptr<Context> context)
: DeviceBase(adapter, descriptor), mGL(functions), mContext(std::move(context)) {}
Device::~Device() {
Destroy();
}
MaybeError Device::Initialize(const DeviceDescriptor* descriptor) {
const OpenGLFunctions& gl = GetGL();
InitTogglesFromDriver();
mFormatTable = BuildGLFormatTable(GetBGRAInternalFormat());
// Use the debug output functionality to get notified about GL errors
// TODO(crbug.com/dawn/1475): add support for the KHR_debug and ARB_debug_output
// extensions
bool hasDebugOutput = gl.IsAtLeastGL(4, 3) || gl.IsAtLeastGLES(3, 2);
if (GetAdapter()->GetInstance()->IsBackendValidationEnabled() && hasDebugOutput) {
gl.Enable(GL_DEBUG_OUTPUT);
gl.Enable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
// Any GL error; dangerous undefined behavior; any shader compiler and linker errors
gl.DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH, 0, nullptr,
GL_TRUE);
// Severe performance warnings; GLSL or other shader compiler and linker warnings;
// use of currently deprecated behavior
gl.DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM, 0, nullptr,
GL_TRUE);
// Performance warnings from redundant state changes; trivial undefined behavior
// This is disabled because we do an incredible amount of redundant state changes.
gl.DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW, 0, nullptr,
GL_FALSE);
// Any message which is not an error or performance concern
gl.DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION, 0,
nullptr, GL_FALSE);
gl.DebugMessageCallback(&OnGLDebugMessage, nullptr);
}
// Set initial state.
gl.Enable(GL_DEPTH_TEST);
gl.Enable(GL_SCISSOR_TEST);
gl.Enable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
if (gl.GetVersion().IsDesktop()) {
// These are not necessary on GLES. The functionality is enabled by default, and
// works by specifying sample counts and SRGB textures, respectively.
gl.Enable(GL_MULTISAMPLE);
gl.Enable(GL_FRAMEBUFFER_SRGB);
}
gl.Enable(GL_SAMPLE_MASK);
return DeviceBase::Initialize(AcquireRef(new Queue(this, &descriptor->defaultQueue)));
}
@ -340,6 +454,9 @@ float Device::GetTimestampPeriodInNS() const {
}
const OpenGLFunctions& Device::GetGL() const {
if (mContext) {
mContext->MakeCurrent();
}
return mGL;
}

View File

@ -39,14 +39,17 @@ namespace dawn::native::opengl {
class Device final : public DeviceBase {
public:
class Context;
static ResultOrError<Ref<Device>> Create(AdapterBase* adapter,
const DeviceDescriptor* descriptor,
const OpenGLFunctions& functions);
const OpenGLFunctions& functions,
std::unique_ptr<Context> context);
~Device() override;
MaybeError Initialize(const DeviceDescriptor* descriptor);
// Contains all the OpenGL entry points, glDoFoo is called via gl.DoFoo.
// Returns all the OpenGL entry points and ensures that the associated
// Context is current.
const OpenGLFunctions& GetGL() const;
const GLFormat& GetGLFormat(const Format& format);
@ -80,10 +83,17 @@ class Device final : public DeviceBase {
float GetTimestampPeriodInNS() const override;
class Context {
public:
virtual ~Context() {}
virtual void MakeCurrent() = 0;
};
private:
Device(AdapterBase* adapter,
const DeviceDescriptor* descriptor,
const OpenGLFunctions& functions);
const OpenGLFunctions& functions,
std::unique_ptr<Context> context);
ResultOrError<Ref<BindGroupBase>> CreateBindGroupImpl(
const BindGroupDescriptor* descriptor) override;
@ -126,6 +136,7 @@ class Device final : public DeviceBase {
std::queue<std::pair<GLsync, ExecutionSerial>> mFencesInFlight;
GLFormatTable mFormatTable;
std::unique_ptr<Context> mContext = nullptr;
};
} // namespace dawn::native::opengl

View File

@ -0,0 +1,42 @@
// Copyright 2022 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn/native/opengl/EGLFunctions.h"
namespace dawn::native::opengl {
void EGLFunctions::Init(void* (*getProc)(const char*)) {
GetProcAddress = reinterpret_cast<PFNEGLGETPROCADDRESSPROC>(getProc);
BindAPI = reinterpret_cast<PFNEGLBINDAPIPROC>(GetProcAddress("eglBindAPI"));
ChooseConfig = reinterpret_cast<PFNEGLCHOOSECONFIGPROC>(GetProcAddress("eglChooseConfig"));
CreateContext = reinterpret_cast<PFNEGLCREATECONTEXTPROC>(GetProcAddress("eglCreateContext"));
CreatePbufferSurface =
reinterpret_cast<PFNEGLCREATEPBUFFERSURFACEPROC>(GetProcAddress("eglCreatePbufferSurface"));
CreatePlatformWindowSurface = reinterpret_cast<PFNEGLCREATEPLATFORMWINDOWSURFACEPROC>(
GetProcAddress("eglCreatePlatformWindowSurface"));
DestroyContext =
reinterpret_cast<PFNEGLDESTROYCONTEXTPROC>(GetProcAddress("eglDestroyContext"));
GetConfigs = reinterpret_cast<PFNEGLGETCONFIGSPROC>(GetProcAddress("eglGetConfigs"));
GetCurrentContext =
reinterpret_cast<PFNEGLGETCURRENTCONTEXTPROC>(GetProcAddress("eglGetCurrentContext"));
GetCurrentDisplay =
reinterpret_cast<PFNEGLGETCURRENTDISPLAYPROC>(GetProcAddress("eglGetCurrentDisplay"));
GetCurrentSurface =
reinterpret_cast<PFNEGLGETCURRENTSURFACEPROC>(GetProcAddress("eglGetCurrentSurface"));
GetDisplay = reinterpret_cast<PFNEGLGETDISPLAYPROC>(GetProcAddress("eglGetDisplay"));
Initialize = reinterpret_cast<PFNEGLINITIALIZEPROC>(GetProcAddress("eglInitialize"));
MakeCurrent = reinterpret_cast<PFNEGLMAKECURRENTPROC>(GetProcAddress("eglMakeCurrent"));
}
} // namespace dawn::native::opengl

View File

@ -0,0 +1,42 @@
// Copyright 2022 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_DAWN_NATIVE_OPENGL_EGLFUNCTIONS_H_
#define SRC_DAWN_NATIVE_OPENGL_EGLFUNCTIONS_H_
#include <EGL/egl.h>
namespace dawn::native::opengl {
struct EGLFunctions {
void Init(void* (*getProc)(const char*));
PFNEGLBINDAPIPROC BindAPI;
PFNEGLCHOOSECONFIGPROC ChooseConfig;
PFNEGLCREATECONTEXTPROC CreateContext;
PFNEGLCREATEPLATFORMWINDOWSURFACEPROC CreatePlatformWindowSurface;
PFNEGLCREATEPBUFFERSURFACEPROC CreatePbufferSurface;
PFNEGLDESTROYCONTEXTPROC DestroyContext;
PFNEGLGETCONFIGSPROC GetConfigs;
PFNEGLGETCURRENTCONTEXTPROC GetCurrentContext;
PFNEGLGETCURRENTDISPLAYPROC GetCurrentDisplay;
PFNEGLGETCURRENTSURFACEPROC GetCurrentSurface;
PFNEGLGETDISPLAYPROC GetDisplay;
PFNEGLGETPROCADDRESSPROC GetProcAddress;
PFNEGLINITIALIZEPROC Initialize;
PFNEGLMAKECURRENTPROC MakeCurrent;
};
} // namespace dawn::native::opengl
#endif // SRC_DAWN_NATIVE_OPENGL_EGLFUNCTIONS_H_

View File

@ -23,11 +23,11 @@
namespace dawn::native::opengl {
AdapterDiscoveryOptions::AdapterDiscoveryOptions()
: AdapterDiscoveryOptionsBase(WGPUBackendType_OpenGL) {}
AdapterDiscoveryOptions::AdapterDiscoveryOptions(WGPUBackendType type)
: AdapterDiscoveryOptionsBase(type) {}
AdapterDiscoveryOptionsES::AdapterDiscoveryOptionsES()
: AdapterDiscoveryOptionsBase(WGPUBackendType_OpenGLES) {}
: AdapterDiscoveryOptions(WGPUBackendType_OpenGLES) {}
DawnSwapChainImplementation CreateNativeSwapChainImpl(WGPUDevice device,
PresentCallback present,

View File

@ -26,9 +26,9 @@ MaybeError OpenGLVersion::Initialize(GetProcAddress getProc) {
return DAWN_INTERNAL_ERROR("Couldn't load glGetString");
}
std::string version = reinterpret_cast<const char*>(getString(GL_VERSION));
const char* version = reinterpret_cast<const char*>(getString(GL_VERSION));
if (version.find("OpenGL ES") != std::string::npos) {
if (strstr(version, "OpenGL ES") != nullptr) {
// ES spec states that the GL_VERSION string will be in the following format:
// "OpenGL ES N.M vendor-specific information"
mStandard = Standard::ES;
@ -36,7 +36,7 @@ MaybeError OpenGLVersion::Initialize(GetProcAddress getProc) {
mMinorVersion = version[12] - '0';
// The minor version shouldn't get to two digits.
ASSERT(version.size() <= 13 || !isdigit(version[13]));
ASSERT(strlen(version) <= 13 || !isdigit(version[13]));
} else {
// OpenGL spec states the GL_VERSION string will be in the following format:
// <version number><space><vendor-specific information>
@ -48,7 +48,7 @@ MaybeError OpenGLVersion::Initialize(GetProcAddress getProc) {
mMinorVersion = version[2] - '0';
// The minor version shouldn't get to two digits.
ASSERT(version.size() <= 3 || !isdigit(version[3]));
ASSERT(strlen(version) <= 3 || !isdigit(version[3]));
}
return {};

View File

@ -103,8 +103,8 @@ wgpu::Device CreateCppDawnDevice() {
return wgpu::Device();
}
// Create the test window and discover adapters using it (esp. for OpenGL)
utils::SetupGLFWWindowHintsForBackend(backendType);
// Create the test window with no client API.
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_FALSE);
window = glfwCreateWindow(640, 480, "Dawn window", nullptr, nullptr);
if (!window) {

View File

@ -422,31 +422,8 @@ std::unique_ptr<dawn::native::Instance> DawnTestEnvironment::CreateInstanceAndDi
auto instance = std::make_unique<dawn::native::Instance>();
instance->EnableBeginCaptureOnStartup(mBeginCaptureOnStartup);
instance->SetBackendValidationLevel(mBackendValidationLevel);
instance->DiscoverDefaultAdapters();
#ifdef DAWN_ENABLE_BACKEND_DESKTOP_GL
if (!glfwInit()) {
return instance;
}
glfwDefaultWindowHints();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
mOpenGLWindow = glfwCreateWindow(400, 400, "Dawn OpenGL test window", nullptr, nullptr);
if (mOpenGLWindow != nullptr) {
glfwMakeContextCurrent(mOpenGLWindow);
dawn::native::opengl::AdapterDiscoveryOptions adapterOptions;
adapterOptions.getProc = reinterpret_cast<void* (*)(const char*)>(glfwGetProcAddress);
instance->DiscoverAdapters(&adapterOptions);
}
#endif // DAWN_ENABLE_BACKEND_DESKTOP_GL
#ifdef DAWN_ENABLE_BACKEND_OPENGLES
ScopedEnvironmentVar angleDefaultPlatform;
if (GetEnvironmentVar("ANGLE_DEFAULT_PLATFORM").first.empty()) {
const char* platform;
if (!mANGLEBackend.empty()) {
@ -458,40 +435,15 @@ std::unique_ptr<dawn::native::Instance> DawnTestEnvironment::CreateInstanceAndDi
platform = "swiftshader";
#endif
}
angleDefaultPlatform.Set("ANGLE_DEFAULT_PLATFORM", platform);
}
if (!glfwInit()) {
return instance;
}
glfwDefaultWindowHints();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
mOpenGLESWindow = glfwCreateWindow(400, 400, "Dawn OpenGLES test window", nullptr, nullptr);
if (mOpenGLESWindow != nullptr) {
glfwMakeContextCurrent(mOpenGLESWindow);
dawn::native::opengl::AdapterDiscoveryOptionsES adapterOptionsES;
adapterOptionsES.getProc = reinterpret_cast<void* (*)(const char*)>(glfwGetProcAddress);
instance->DiscoverAdapters(&adapterOptionsES);
glfwWindowHint(GLFW_VISIBLE, GLFW_TRUE);
SetEnvironmentVar("ANGLE_DEFAULT_PLATFORM", platform);
}
#endif // DAWN_ENABLE_BACKEND_OPENGLES
instance->DiscoverDefaultAdapters();
return instance;
}
GLFWwindow* DawnTestEnvironment::GetOpenGLWindow() const {
return mOpenGLWindow;
}
GLFWwindow* DawnTestEnvironment::GetOpenGLESWindow() const {
return mOpenGLESWindow;
}
void DawnTestEnvironment::SelectPreferredAdapterProperties(const dawn::native::Instance* instance) {
// Get the first available preferred device type.
wgpu::AdapterType preferredDeviceType = static_cast<wgpu::AdapterType>(-1);
@ -1129,17 +1081,6 @@ void DawnTestBase::SetUp() {
ASSERT(device);
queue = device.GetQueue();
#if defined(DAWN_ENABLE_BACKEND_DESKTOP_GL)
if (IsOpenGL()) {
glfwMakeContextCurrent(gTestEnv->GetOpenGLWindow());
}
#endif // defined(DAWN_ENABLE_BACKEND_DESKTOP_GL)
#if defined(DAWN_ENABLE_BACKEND_OPENGLES)
if (IsOpenGLES()) {
glfwMakeContextCurrent(gTestEnv->GetOpenGLESWindow());
}
#endif // defined(DAWN_ENABLE_BACKEND_OPENGLES)
}
void DawnTestBase::TearDown() {

View File

@ -273,8 +273,6 @@ class DawnTestEnvironment : public testing::Environment {
std::vector<TestAdapterProperties> mAdapterProperties;
std::unique_ptr<utils::PlatformDebugLogger> mPlatformDebugLogger;
GLFWwindow* mOpenGLWindow;
GLFWwindow* mOpenGLESWindow;
};
class DawnTestBase {

View File

@ -155,81 +155,6 @@ TEST(AdapterDiscoveryTests, OnlyMetal) {
}
#endif // defined(DAWN_ENABLE_BACKEND_METAL)
#if defined(DAWN_ENABLE_BACKEND_DESKTOP_GL)
// Test discovering only desktop OpenGL adapters
TEST(AdapterDiscoveryTests, OnlyDesktopGL) {
if (!glfwInit()) {
GTEST_SKIP() << "glfwInit() failed";
}
glfwDefaultWindowHints();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
GLFWwindow* window = glfwCreateWindow(400, 400, "Dawn OpenGL test window", nullptr, nullptr);
glfwMakeContextCurrent(window);
dawn::native::Instance instance;
dawn::native::opengl::AdapterDiscoveryOptions options;
options.getProc = reinterpret_cast<void* (*)(const char*)>(glfwGetProcAddress);
instance.DiscoverAdapters(&options);
glfwWindowHint(GLFW_VISIBLE, GLFW_TRUE);
const auto& adapters = instance.GetAdapters();
for (const auto& adapter : adapters) {
wgpu::AdapterProperties properties;
adapter.GetProperties(&properties);
EXPECT_EQ(properties.backendType, wgpu::BackendType::OpenGL);
}
glfwDestroyWindow(window);
}
#endif // defined(DAWN_ENABLE_BACKEND_DESKTOP_GL)
#if defined(DAWN_ENABLE_BACKEND_OPENGLES)
// Test discovering only OpenGLES adapters
TEST(AdapterDiscoveryTests, OnlyOpenGLES) {
ScopedEnvironmentVar angleDefaultPlatform;
if (GetEnvironmentVar("ANGLE_DEFAULT_PLATFORM").first.empty()) {
angleDefaultPlatform.Set("ANGLE_DEFAULT_PLATFORM", "swiftshader");
}
if (!glfwInit()) {
GTEST_SKIP() << "glfwInit() failed";
}
glfwDefaultWindowHints();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
GLFWwindow* window = glfwCreateWindow(400, 400, "Dawn OpenGLES test window", nullptr, nullptr);
glfwMakeContextCurrent(window);
dawn::native::Instance instance;
dawn::native::opengl::AdapterDiscoveryOptionsES options;
options.getProc = reinterpret_cast<void* (*)(const char*)>(glfwGetProcAddress);
instance.DiscoverAdapters(&options);
glfwWindowHint(GLFW_VISIBLE, GLFW_TRUE);
const auto& adapters = instance.GetAdapters();
for (const auto& adapter : adapters) {
wgpu::AdapterProperties properties;
adapter.GetProperties(&properties);
EXPECT_EQ(properties.backendType, wgpu::BackendType::OpenGLES);
}
glfwDestroyWindow(window);
}
#endif // defined(DAWN_ENABLE_BACKEND_OPENGLES)
#if defined(DAWN_ENABLE_BACKEND_METAL) && defined(DAWN_ENABLE_BACKEND_VULKAN)
// Test discovering the Metal backend, then the Vulkan backend
// does not duplicate adapters.

View File

@ -37,10 +37,7 @@ class SwapChainTests : public DawnTest {
GTEST_SKIP();
}
// The SwapChainTests don't create OpenGL contexts so we don't need to call
// SetupGLFWWindowHintsForBackend. Set GLFW_NO_API anyway to avoid GLFW bringing up a GL
// context that we won't use.
ASSERT_TRUE(!IsOpenGL());
// Set GLFW_NO_API to avoid GLFW bringing up a GL context that we won't use.
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
window = glfwCreateWindow(400, 400, "SwapChainValidationTests window", nullptr, nullptr);

View File

@ -34,10 +34,7 @@ class SwapChainValidationTests : public DawnTest {
});
DAWN_TEST_UNSUPPORTED_IF(!glfwInit());
// The SwapChainValidationTests don't create devices so we don't need to call
// SetupGLFWWindowHintsForBackend. Set GLFW_NO_API anyway to avoid GLFW bringing up a GL
// context that we won't use.
ASSERT_TRUE(!IsOpenGL());
// Set GLFW_NO_API to avoid GLFW bringing up a GL context that we won't use.
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
window = glfwCreateWindow(400, 400, "SwapChainValidationTests window", nullptr, nullptr);

View File

@ -68,9 +68,7 @@ class WindowSurfaceInstanceTests : public testing::Test {
}
GLFWwindow* CreateWindow() {
// The WindowSurfaceInstance tests don't create devices so we don't need to call
// SetupGLFWWindowHintsForBackend. Set GLFW_NO_API anyway to avoid GLFW bringing up a GL
// context that we won't use.
// Set GLFW_NO_API to avoid GLFW bringing up a GL context that we won't use.
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
mWindow = glfwCreateWindow(400, 400, "WindowSurfaceInstanceTests window", nullptr, nullptr);
return mWindow;

View File

@ -16,12 +16,6 @@
#include "dawn/common/Compiler.h"
#include "GLFW/glfw3.h"
#if defined(DAWN_ENABLE_BACKEND_OPENGL)
#include "dawn/native/OpenGLBackend.h"
#endif // defined(DAWN_ENABLE_BACKEND_OPENGL)
namespace utils {
#if defined(DAWN_ENABLE_BACKEND_D3D12)
@ -43,29 +37,6 @@ BackendBinding* CreateVulkanBinding(GLFWwindow* window, WGPUDevice device);
BackendBinding::BackendBinding(GLFWwindow* window, WGPUDevice device)
: mWindow(window), mDevice(device) {}
void DiscoverAdapter(dawn::native::Instance* instance, GLFWwindow* window, wgpu::BackendType type) {
DAWN_UNUSED(type);
DAWN_UNUSED(window);
if (type == wgpu::BackendType::OpenGL || type == wgpu::BackendType::OpenGLES) {
#if defined(DAWN_ENABLE_BACKEND_OPENGL)
glfwMakeContextCurrent(window);
auto getProc = reinterpret_cast<void* (*)(const char*)>(glfwGetProcAddress);
if (type == wgpu::BackendType::OpenGL) {
dawn::native::opengl::AdapterDiscoveryOptions adapterOptions;
adapterOptions.getProc = getProc;
instance->DiscoverAdapters(&adapterOptions);
} else {
dawn::native::opengl::AdapterDiscoveryOptionsES adapterOptions;
adapterOptions.getProc = getProc;
instance->DiscoverAdapters(&adapterOptions);
}
#endif // defined(DAWN_ENABLE_BACKEND_OPENGL)
} else {
instance->DiscoverDefaultAdapters();
}
}
BackendBinding* CreateBinding(wgpu::BackendType type, GLFWwindow* window, WGPUDevice device) {
switch (type) {
#if defined(DAWN_ENABLE_BACKEND_D3D12)

View File

@ -32,26 +32,6 @@
namespace utils {
void SetupGLFWWindowHintsForBackend(wgpu::BackendType type) {
if (type == wgpu::BackendType::OpenGL) {
// Ask for OpenGL 4.4 which is what the GL backend requires for compute shaders and
// texture views.
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
} else if (type == wgpu::BackendType::OpenGLES) {
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
} else {
// Without this GLFW will initialize a GL context on the window, which prevents using
// the window with other APIs (by crashing in weird ways).
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
}
}
wgpu::Surface CreateSurfaceForWindow(const wgpu::Instance& instance, GLFWwindow* window) {
std::unique_ptr<wgpu::ChainedStruct> chainedDescriptor =
SetupWindowAndGetSurfaceDescriptor(window);

View File

@ -23,10 +23,6 @@ struct GLFWwindow;
namespace utils {
// Adds all the necessary glfwWindowHint calls for the next GLFWwindow created to be used with
// the specified backend.
void SetupGLFWWindowHintsForBackend(wgpu::BackendType type);
// Does the necessary setup on the GLFWwindow to allow creating a wgpu::Surface with it and
// calls `instance.CreateSurface` with the correct descriptor for this window.
// Returns a null wgpu::Surface on failure.