From ba84fb2977372f456ae026e2ff1c5734d55a7310 Mon Sep 17 00:00:00 2001 From: Corentin Wallez Date: Mon, 22 Jul 2019 10:02:49 +0000 Subject: [PATCH] OpenGL: Add support for backend validation This uses the OpenGL debug ouput functionality to make the driver call us back when an error happens so we can ASSERT and fail. BUG=dawn:190 Change-Id: I4b6d7a860384dfeccc1c37383fd4cbdc09d7dc05 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/9204 Commit-Queue: Corentin Wallez Reviewed-by: Kai Ninomiya --- generator/templates/opengl/opengl_platform.h | 16 +--- src/dawn_native/opengl/BackendGL.cpp | 98 +++++++++++++++++++- src/dawn_native/opengl/OpenGLFunctions.cpp | 10 ++ src/dawn_native/opengl/OpenGLFunctions.h | 3 + 4 files changed, 112 insertions(+), 15 deletions(-) diff --git a/generator/templates/opengl/opengl_platform.h b/generator/templates/opengl/opengl_platform.h index 182f50ab35..9b2a53aeac 100644 --- a/generator/templates/opengl/opengl_platform.h +++ b/generator/templates/opengl/opengl_platform.h @@ -44,20 +44,8 @@ using GLDEBUGPROC = void(KHRONOS_APIENTRY*)(GLenum source, GLsizei length, const GLchar* message, const void* userParam); -using GLDEBUGPROCARB = void(KHRONOS_APIENTRY*)(GLenum source, - GLenum type, - GLuint id, - GLenum severity, - GLsizei length, - const GLchar* message, - const void* userParam); -using GLDEBUGPROCKHR = void(KHRONOS_APIENTRY*)(GLenum source, - GLenum type, - GLuint id, - GLenum severity, - GLsizei length, - const GLchar* message, - const void* userParam); +using GLDEBUGPROCARB = GLDEBUGPROC; +using GLDEBUGPROCKHR = GLDEBUGPROC; using GLDEBUGPROCAMD = void(KHRONOS_APIENTRY*)(GLuint id, GLenum category, GLenum severity, diff --git a/src/dawn_native/opengl/BackendGL.cpp b/src/dawn_native/opengl/BackendGL.cpp index 94fc2fa292..c1689132c7 100644 --- a/src/dawn_native/opengl/BackendGL.cpp +++ b/src/dawn_native/opengl/BackendGL.cpp @@ -15,10 +15,12 @@ #include "dawn_native/opengl/BackendGL.h" #include "common/Constants.h" +#include "dawn_native/Instance.h" #include "dawn_native/OpenGLBackend.h" #include "dawn_native/opengl/DeviceGL.h" #include +#include namespace dawn_native { namespace opengl { @@ -47,7 +49,71 @@ namespace dawn_native { namespace opengl { } return vendorId; } - } // 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) { + std::cout << "OpenGL error:" << std::endl; + std::cout << " Source: " << sourceText << std::endl; + std::cout << " ID: " << id << std::endl; + std::cout << " Severity: " << severityText << std::endl; + std::cout << " Message: " << message << std::endl; + + // Abort on an error when in Debug mode. + UNREACHABLE(); + } + } + + } // anonymous namespace // The OpenGL backend's Adapter. @@ -60,6 +126,36 @@ namespace dawn_native { namespace opengl { // Use getProc to populate the dispatch table DAWN_TRY(mFunctions.Initialize(options->getProc)); + // 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); diff --git a/src/dawn_native/opengl/OpenGLFunctions.cpp b/src/dawn_native/opengl/OpenGLFunctions.cpp index d56aa24116..5432715e17 100644 --- a/src/dawn_native/opengl/OpenGLFunctions.cpp +++ b/src/dawn_native/opengl/OpenGLFunctions.cpp @@ -56,4 +56,14 @@ namespace dawn_native { namespace opengl { return {}; } + bool OpenGLFunctions::IsAtLeastGL(uint32_t majorVersion, uint32_t minorVersion) { + return mStandard == Standard::Desktop && + std::tie(mMajorVersion, mMinorVersion) >= std::tie(majorVersion, minorVersion); + } + + bool OpenGLFunctions::IsAtLeastGLES(uint32_t majorVersion, uint32_t minorVersion) { + return mStandard == Standard::ES && + std::tie(mMajorVersion, mMinorVersion) >= std::tie(majorVersion, minorVersion); + } + }} // namespace dawn_native::opengl diff --git a/src/dawn_native/opengl/OpenGLFunctions.h b/src/dawn_native/opengl/OpenGLFunctions.h index 6f737ec9b9..9fe81a5759 100644 --- a/src/dawn_native/opengl/OpenGLFunctions.h +++ b/src/dawn_native/opengl/OpenGLFunctions.h @@ -23,6 +23,9 @@ namespace dawn_native { namespace opengl { public: MaybeError Initialize(GetProcAddress getProc); + bool IsAtLeastGL(uint32_t majorVersion, uint32_t minorVersion); + bool IsAtLeastGLES(uint32_t majorVersion, uint32_t minorVersion); + private: uint32_t mMajorVersion; uint32_t mMinorVersion;