Add preliminary OpenGL ES and EGL support to Dawn.

This is enough to get all of the sample apps running on a conformant ES 3.1 implementation, such as ANGLE/Vk or NVidia's OpenGL ES Linux driver.

Implements a new opengl::AdapterDiscoveryOptionsES subclass to specify its creation at adapter discovery time.
Adds a "-b opengles" command-line flag to the code samples.
Asserts on a call to glShaderStorageBlockBinding() on ES.
Works around missing indexed draw buffers support by asserting when a non-0 color attachment is specified.
Works around missing glClearTexSubImage() by asserting. :/
These will likely require front-end validation.

BUG=dawn:580
Change-Id: I4a4240ca695a22388c55073fd2aee0323cd4afc9
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/31000
Reviewed-by: Stephen White <senorblanco@chromium.org>
Commit-Queue: Stephen White <senorblanco@chromium.org>
This commit is contained in:
Stephen White 2020-11-24 20:57:23 +00:00 committed by Commit Bot service account
parent 90bac683b4
commit 70102b7190
15 changed files with 113 additions and 40 deletions

View File

@ -213,12 +213,17 @@ bool InitSample(int argc, const char** argv) {
backendType = wgpu::BackendType::OpenGL;
continue;
}
if (i < argc && std::string("opengles") == argv[i]) {
backendType = wgpu::BackendType::OpenGLES;
continue;
}
if (i < argc && std::string("vulkan") == argv[i]) {
backendType = wgpu::BackendType::Vulkan;
continue;
}
fprintf(stderr,
"--backend expects a backend name (opengl, metal, d3d12, null, vulkan)\n");
"--backend expects a backend name (opengl, opengles, metal, d3d12, null, "
"vulkan)\n");
return false;
}
if (std::string("-c") == argv[i] || std::string("--command-buffer") == argv[i]) {

View File

@ -69,9 +69,10 @@ namespace dawn_native {
return BackendType::OpenGL;
case wgpu::BackendType::Vulkan:
return BackendType::Vulkan;
case wgpu::BackendType::OpenGLES:
return BackendType::OpenGLES;
case wgpu::BackendType::D3D11:
case wgpu::BackendType::OpenGLES:
UNREACHABLE();
}
}

View File

@ -40,7 +40,7 @@ namespace dawn_native {
#endif // defined(DAWN_ENABLE_BACKEND_NULL)
#if defined(DAWN_ENABLE_BACKEND_OPENGL)
namespace opengl {
BackendConnection* Connect(InstanceBase* instance);
BackendConnection* Connect(InstanceBase* instance, wgpu::BackendType backendType);
}
#endif // defined(DAWN_ENABLE_BACKEND_OPENGL)
#if defined(DAWN_ENABLE_BACKEND_VULKAN)
@ -147,7 +147,8 @@ namespace dawn_native {
# endif // defined(DAWN_ENABLE_SWIFTSHADER)
#endif // defined(DAWN_ENABLE_BACKEND_VULKAN)
#if defined(DAWN_ENABLE_BACKEND_OPENGL)
Register(opengl::Connect(this), wgpu::BackendType::OpenGL);
Register(opengl::Connect(this, wgpu::BackendType::OpenGL), wgpu::BackendType::OpenGL);
Register(opengl::Connect(this, wgpu::BackendType::OpenGLES), wgpu::BackendType::OpenGLES);
#endif // defined(DAWN_ENABLE_BACKEND_OPENGL)
#if defined(DAWN_ENABLE_BACKEND_NULL)
Register(null::Connect(this), wgpu::BackendType::Null);

View File

@ -119,12 +119,18 @@ namespace dawn_native { namespace opengl {
class Adapter : public AdapterBase {
public:
Adapter(InstanceBase* instance) : AdapterBase(instance, wgpu::BackendType::OpenGL) {
Adapter(InstanceBase* instance, wgpu::BackendType backendType)
: AdapterBase(instance, backendType) {
}
MaybeError Initialize(const AdapterDiscoveryOptions* options) {
// Use getProc to populate the dispatch table
DAWN_TRY(mFunctions.Initialize(options->getProc));
if (mFunctions.GetVersion().IsES()) {
ASSERT(GetBackendType() == wgpu::BackendType::OpenGLES);
} else {
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
@ -160,7 +166,9 @@ namespace dawn_native { namespace opengl {
mFunctions.Enable(GL_DEPTH_TEST);
mFunctions.Enable(GL_SCISSOR_TEST);
mFunctions.Enable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
mFunctions.Enable(GL_MULTISAMPLE);
if (mFunctions.GetVersion().IsDesktop()) {
mFunctions.Enable(GL_MULTISAMPLE);
}
mFunctions.Enable(GL_FRAMEBUFFER_SRGB);
mFunctions.Enable(GL_SAMPLE_MASK);
@ -229,8 +237,8 @@ namespace dawn_native { namespace opengl {
// Implementation of the OpenGL backend's BackendConnection
Backend::Backend(InstanceBase* instance)
: BackendConnection(instance, wgpu::BackendType::OpenGL) {
Backend::Backend(InstanceBase* instance, wgpu::BackendType backendType)
: BackendConnection(instance, backendType) {
}
std::vector<std::unique_ptr<AdapterBase>> Backend::DiscoverDefaultAdapters() {
@ -246,7 +254,7 @@ namespace dawn_native { namespace opengl {
return DAWN_VALIDATION_ERROR("The OpenGL backend can only create a single adapter");
}
ASSERT(optionsBase->backendType == WGPUBackendType_OpenGL);
ASSERT(static_cast<wgpu::BackendType>(optionsBase->backendType) == GetType());
const AdapterDiscoveryOptions* options =
static_cast<const AdapterDiscoveryOptions*>(optionsBase);
@ -254,7 +262,8 @@ namespace dawn_native { namespace opengl {
return DAWN_VALIDATION_ERROR("AdapterDiscoveryOptions::getProc must be set");
}
std::unique_ptr<Adapter> adapter = std::make_unique<Adapter>(GetInstance());
std::unique_ptr<Adapter> adapter = std::make_unique<Adapter>(
GetInstance(), static_cast<wgpu::BackendType>(optionsBase->backendType));
DAWN_TRY(adapter->Initialize(options));
mCreatedAdapter = true;
@ -263,8 +272,8 @@ namespace dawn_native { namespace opengl {
return std::move(adapters);
}
BackendConnection* Connect(InstanceBase* instance) {
return new Backend(instance);
BackendConnection* Connect(InstanceBase* instance, wgpu::BackendType backendType) {
return new Backend(instance, backendType);
}
}} // namespace dawn_native::opengl

View File

@ -21,7 +21,7 @@ namespace dawn_native { namespace opengl {
class Backend : public BackendConnection {
public:
Backend(InstanceBase* instance);
Backend(InstanceBase* instance, wgpu::BackendType backendType);
std::vector<std::unique_ptr<AdapterBase>> DiscoverDefaultAdapters() override;
ResultOrError<std::vector<std::unique_ptr<AdapterBase>>> DiscoverAdapters(

View File

@ -133,7 +133,7 @@ namespace dawn_native { namespace opengl {
MaybeError Buffer::MapAtCreationImpl() {
const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
gl.BindBuffer(GL_ARRAY_BUFFER, mBuffer);
mMappedData = gl.MapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
mMappedData = gl.MapBufferRange(GL_ARRAY_BUFFER, 0, GetSize(), GL_MAP_WRITE_BIT);
return {};
}

View File

@ -944,7 +944,7 @@ namespace dawn_native { namespace opengl {
// Load op - color
if (attachmentInfo->loadOp == wgpu::LoadOp::Clear) {
gl.ColorMaski(i, true, true, true, true);
gl.ColorMask(true, true, true, true);
wgpu::TextureComponentType baseType =
attachmentInfo->view->GetFormat().GetAspectInfo(Aspect::Color).baseType;

View File

@ -27,6 +27,10 @@ namespace dawn_native { namespace opengl {
: AdapterDiscoveryOptionsBase(WGPUBackendType_OpenGL) {
}
AdapterDiscoveryOptionsES::AdapterDiscoveryOptionsES()
: AdapterDiscoveryOptionsBase(WGPUBackendType_OpenGLES) {
}
DawnSwapChainImplementation CreateNativeSwapChainImpl(WGPUDevice device,
PresentCallback present,
void* presentUserdata) {

View File

@ -134,8 +134,14 @@ namespace dawn_native { namespace opengl {
GLuint location = gl.GetProgramResourceIndex(
mProgram, GL_SHADER_STORAGE_BLOCK, name.c_str());
if (location != GL_INVALID_INDEX) {
gl.ShaderStorageBlockBinding(mProgram, location,
indices[group][bindingIndex]);
if (gl.GetVersion().IsES()) {
// TODO(crbug.com/dawn/584): Figure out a substitute for
// glShaderStorageBlockBinding on ES or add additional validation.
ASSERT(false);
} else {
gl.ShaderStorageBlockBinding(mProgram, location,
indices[group][bindingIndex]);
}
}
break;
}

View File

@ -106,23 +106,44 @@ namespace dawn_native { namespace opengl {
ColorAttachmentIndex attachment,
const ColorStateDescriptor* descriptor) {
GLuint colorBuffer = static_cast<GLuint>(static_cast<uint8_t>(attachment));
if (BlendEnabled(descriptor)) {
gl.Enablei(GL_BLEND, colorBuffer);
gl.BlendEquationSeparatei(colorBuffer,
GLBlendMode(descriptor->colorBlend.operation),
GLBlendMode(descriptor->alphaBlend.operation));
gl.BlendFuncSeparatei(colorBuffer,
GLBlendFactor(descriptor->colorBlend.srcFactor, false),
GLBlendFactor(descriptor->colorBlend.dstFactor, false),
GLBlendFactor(descriptor->alphaBlend.srcFactor, true),
GLBlendFactor(descriptor->alphaBlend.dstFactor, true));
if (gl.IsAtLeastGL(3, 0) || gl.IsAtLeastGLES(3, 2)) {
if (BlendEnabled(descriptor)) {
gl.Enablei(GL_BLEND, colorBuffer);
gl.BlendEquationSeparatei(colorBuffer,
GLBlendMode(descriptor->colorBlend.operation),
GLBlendMode(descriptor->alphaBlend.operation));
gl.BlendFuncSeparatei(colorBuffer,
GLBlendFactor(descriptor->colorBlend.srcFactor, false),
GLBlendFactor(descriptor->colorBlend.dstFactor, false),
GLBlendFactor(descriptor->alphaBlend.srcFactor, true),
GLBlendFactor(descriptor->alphaBlend.dstFactor, true));
} else {
gl.Disablei(GL_BLEND, colorBuffer);
}
gl.ColorMaski(colorBuffer, descriptor->writeMask & wgpu::ColorWriteMask::Red,
descriptor->writeMask & wgpu::ColorWriteMask::Green,
descriptor->writeMask & wgpu::ColorWriteMask::Blue,
descriptor->writeMask & wgpu::ColorWriteMask::Alpha);
} else {
gl.Disablei(GL_BLEND, colorBuffer);
// TODO(crbug.com/dawn/582): Add validation to prevent this as it is not supported
// on GLES < 3.2.
DAWN_ASSERT(colorBuffer == 0);
if (BlendEnabled(descriptor)) {
gl.Enable(GL_BLEND);
gl.BlendEquationSeparate(GLBlendMode(descriptor->colorBlend.operation),
GLBlendMode(descriptor->alphaBlend.operation));
gl.BlendFuncSeparate(GLBlendFactor(descriptor->colorBlend.srcFactor, false),
GLBlendFactor(descriptor->colorBlend.dstFactor, false),
GLBlendFactor(descriptor->alphaBlend.srcFactor, true),
GLBlendFactor(descriptor->alphaBlend.dstFactor, true));
} else {
gl.Disable(GL_BLEND);
}
gl.ColorMask(descriptor->writeMask & wgpu::ColorWriteMask::Red,
descriptor->writeMask & wgpu::ColorWriteMask::Green,
descriptor->writeMask & wgpu::ColorWriteMask::Blue,
descriptor->writeMask & wgpu::ColorWriteMask::Alpha);
}
gl.ColorMaski(colorBuffer, descriptor->writeMask & wgpu::ColorWriteMask::Red,
descriptor->writeMask & wgpu::ColorWriteMask::Green,
descriptor->writeMask & wgpu::ColorWriteMask::Blue,
descriptor->writeMask & wgpu::ColorWriteMask::Alpha);
}
GLuint OpenGLStencilOperation(wgpu::StencilOperation stencilOperation) {

View File

@ -323,10 +323,16 @@ namespace dawn_native { namespace opengl {
// Skip lazy clears if already initialized.
continue;
}
gl.ClearTexSubImage(mHandle, static_cast<GLint>(level), 0, 0,
static_cast<GLint>(layer), mipSize.width,
mipSize.height, 1, glFormat.format, glFormat.type,
clearColorData.data());
if (gl.IsAtLeastGL(4, 4)) {
gl.ClearTexSubImage(mHandle, static_cast<GLint>(level), 0, 0,
static_cast<GLint>(layer), mipSize.width,
mipSize.height, 1, glFormat.format, glFormat.type,
clearColorData.data());
} else {
// TODO(crbug.com/dawn/581): Implement a fallback path on OpenGL ES
// because it doesn't support glClearTexSubImage.
ASSERT(false);
}
}
}
}

View File

@ -45,6 +45,7 @@ namespace dawn_native {
Metal,
Null,
OpenGL,
OpenGLES,
Vulkan,
};

View File

@ -26,6 +26,12 @@ namespace dawn_native { namespace opengl {
void* (*getProc)(const char*);
};
struct DAWN_NATIVE_EXPORT AdapterDiscoveryOptionsES : public AdapterDiscoveryOptionsBase {
AdapterDiscoveryOptionsES();
void* (*getProc)(const char*);
};
using PresentCallback = void (*)(void*);
DAWN_NATIVE_EXPORT DawnSwapChainImplementation
CreateNativeSwapChainImpl(WGPUDevice device, PresentCallback present, void* presentUserdata);

View File

@ -50,12 +50,19 @@ namespace utils {
DAWN_UNUSED(type);
DAWN_UNUSED(window);
if (type == wgpu::BackendType::OpenGL) {
if (type == wgpu::BackendType::OpenGL || type == wgpu::BackendType::OpenGLES) {
#if defined(DAWN_ENABLE_BACKEND_OPENGL)
glfwMakeContextCurrent(window);
dawn_native::opengl::AdapterDiscoveryOptions adapterOptions;
adapterOptions.getProc = reinterpret_cast<void* (*)(const char*)>(glfwGetProcAddress);
instance->DiscoverAdapters(&adapterOptions);
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();
@ -81,6 +88,7 @@ namespace utils {
#if defined(DAWN_ENABLE_BACKEND_OPENGL)
case wgpu::BackendType::OpenGL:
case wgpu::BackendType::OpenGLES:
return CreateOpenGLBinding(window, device);
#endif

View File

@ -36,6 +36,11 @@ namespace utils {
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).