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; backendType = wgpu::BackendType::OpenGL;
continue; continue;
} }
if (i < argc && std::string("opengles") == argv[i]) {
backendType = wgpu::BackendType::OpenGLES;
continue;
}
if (i < argc && std::string("vulkan") == argv[i]) { if (i < argc && std::string("vulkan") == argv[i]) {
backendType = wgpu::BackendType::Vulkan; backendType = wgpu::BackendType::Vulkan;
continue; continue;
} }
fprintf(stderr, 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; return false;
} }
if (std::string("-c") == argv[i] || std::string("--command-buffer") == argv[i]) { if (std::string("-c") == argv[i] || std::string("--command-buffer") == argv[i]) {

View File

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

View File

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

View File

@ -119,12 +119,18 @@ namespace dawn_native { namespace opengl {
class Adapter : public AdapterBase { class Adapter : public AdapterBase {
public: public:
Adapter(InstanceBase* instance) : AdapterBase(instance, wgpu::BackendType::OpenGL) { Adapter(InstanceBase* instance, wgpu::BackendType backendType)
: AdapterBase(instance, backendType) {
} }
MaybeError Initialize(const AdapterDiscoveryOptions* options) { MaybeError Initialize(const AdapterDiscoveryOptions* options) {
// Use getProc to populate the dispatch table // Use getProc to populate the dispatch table
DAWN_TRY(mFunctions.Initialize(options->getProc)); 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 // 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 // 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_DEPTH_TEST);
mFunctions.Enable(GL_SCISSOR_TEST); mFunctions.Enable(GL_SCISSOR_TEST);
mFunctions.Enable(GL_PRIMITIVE_RESTART_FIXED_INDEX); 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_FRAMEBUFFER_SRGB);
mFunctions.Enable(GL_SAMPLE_MASK); mFunctions.Enable(GL_SAMPLE_MASK);
@ -229,8 +237,8 @@ namespace dawn_native { namespace opengl {
// Implementation of the OpenGL backend's BackendConnection // Implementation of the OpenGL backend's BackendConnection
Backend::Backend(InstanceBase* instance) Backend::Backend(InstanceBase* instance, wgpu::BackendType backendType)
: BackendConnection(instance, wgpu::BackendType::OpenGL) { : BackendConnection(instance, backendType) {
} }
std::vector<std::unique_ptr<AdapterBase>> Backend::DiscoverDefaultAdapters() { 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"); 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 = const AdapterDiscoveryOptions* options =
static_cast<const AdapterDiscoveryOptions*>(optionsBase); static_cast<const AdapterDiscoveryOptions*>(optionsBase);
@ -254,7 +262,8 @@ namespace dawn_native { namespace opengl {
return DAWN_VALIDATION_ERROR("AdapterDiscoveryOptions::getProc must be set"); 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)); DAWN_TRY(adapter->Initialize(options));
mCreatedAdapter = true; mCreatedAdapter = true;
@ -263,8 +272,8 @@ namespace dawn_native { namespace opengl {
return std::move(adapters); return std::move(adapters);
} }
BackendConnection* Connect(InstanceBase* instance) { BackendConnection* Connect(InstanceBase* instance, wgpu::BackendType backendType) {
return new Backend(instance); return new Backend(instance, backendType);
} }
}} // namespace dawn_native::opengl }} // namespace dawn_native::opengl

View File

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

View File

@ -133,7 +133,7 @@ namespace dawn_native { namespace opengl {
MaybeError Buffer::MapAtCreationImpl() { MaybeError Buffer::MapAtCreationImpl() {
const OpenGLFunctions& gl = ToBackend(GetDevice())->gl; const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
gl.BindBuffer(GL_ARRAY_BUFFER, mBuffer); 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 {}; return {};
} }

View File

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

View File

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

View File

@ -134,8 +134,14 @@ namespace dawn_native { namespace opengl {
GLuint location = gl.GetProgramResourceIndex( GLuint location = gl.GetProgramResourceIndex(
mProgram, GL_SHADER_STORAGE_BLOCK, name.c_str()); mProgram, GL_SHADER_STORAGE_BLOCK, name.c_str());
if (location != GL_INVALID_INDEX) { if (location != GL_INVALID_INDEX) {
gl.ShaderStorageBlockBinding(mProgram, location, if (gl.GetVersion().IsES()) {
indices[group][bindingIndex]); // 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; break;
} }

View File

@ -106,23 +106,44 @@ namespace dawn_native { namespace opengl {
ColorAttachmentIndex attachment, ColorAttachmentIndex attachment,
const ColorStateDescriptor* descriptor) { const ColorStateDescriptor* descriptor) {
GLuint colorBuffer = static_cast<GLuint>(static_cast<uint8_t>(attachment)); GLuint colorBuffer = static_cast<GLuint>(static_cast<uint8_t>(attachment));
if (BlendEnabled(descriptor)) { if (gl.IsAtLeastGL(3, 0) || gl.IsAtLeastGLES(3, 2)) {
gl.Enablei(GL_BLEND, colorBuffer); if (BlendEnabled(descriptor)) {
gl.BlendEquationSeparatei(colorBuffer, gl.Enablei(GL_BLEND, colorBuffer);
GLBlendMode(descriptor->colorBlend.operation), gl.BlendEquationSeparatei(colorBuffer,
GLBlendMode(descriptor->alphaBlend.operation)); GLBlendMode(descriptor->colorBlend.operation),
gl.BlendFuncSeparatei(colorBuffer, GLBlendMode(descriptor->alphaBlend.operation));
GLBlendFactor(descriptor->colorBlend.srcFactor, false), gl.BlendFuncSeparatei(colorBuffer,
GLBlendFactor(descriptor->colorBlend.dstFactor, false), GLBlendFactor(descriptor->colorBlend.srcFactor, false),
GLBlendFactor(descriptor->alphaBlend.srcFactor, true), GLBlendFactor(descriptor->colorBlend.dstFactor, false),
GLBlendFactor(descriptor->alphaBlend.dstFactor, true)); 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 { } 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) { GLuint OpenGLStencilOperation(wgpu::StencilOperation stencilOperation) {

View File

@ -323,10 +323,16 @@ namespace dawn_native { namespace opengl {
// Skip lazy clears if already initialized. // Skip lazy clears if already initialized.
continue; continue;
} }
gl.ClearTexSubImage(mHandle, static_cast<GLint>(level), 0, 0, if (gl.IsAtLeastGL(4, 4)) {
static_cast<GLint>(layer), mipSize.width, gl.ClearTexSubImage(mHandle, static_cast<GLint>(level), 0, 0,
mipSize.height, 1, glFormat.format, glFormat.type, static_cast<GLint>(layer), mipSize.width,
clearColorData.data()); 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, Metal,
Null, Null,
OpenGL, OpenGL,
OpenGLES,
Vulkan, Vulkan,
}; };

View File

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

View File

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

View File

@ -36,6 +36,11 @@ namespace utils {
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 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 { } else {
// Without this GLFW will initialize a GL context on the window, which prevents using // Without this GLFW will initialize a GL context on the window, which prevents using
// the window with other APIs (by crashing in weird ways). // the window with other APIs (by crashing in weird ways).