diff options
| author | Brian Salomon <bsalomon@google.com> | 2017-11-16 10:17:20 -0500 |
|---|---|---|
| committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-11-16 16:30:53 +0000 |
| commit | 5627d65146cb92624b682389e017d488872228c7 (patch) | |
| tree | 9b90fe789341a23d05dc0e896eeafc1a20b70a26 /tools/gpu/gl/command_buffer/GLTestContext_command_buffer.cpp | |
| parent | 47f6029d3dc5ee9e484931a13a14dcbe9d3f23d3 (diff) | |
Add method to sk_gpu_test::TestContext to automatically restore the previous context.
The motivation for this is to allow a GM to create a GL context, do some some work in it, and then return to the context that was set when it was invoked.
Change-Id: Ie8496072a10f8f3ff36a08889e593a6ca961b61a
Reviewed-on: https://skia-review.googlesource.com/70720
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Diffstat (limited to 'tools/gpu/gl/command_buffer/GLTestContext_command_buffer.cpp')
| -rw-r--r-- | tools/gpu/gl/command_buffer/GLTestContext_command_buffer.cpp | 86 |
1 files changed, 72 insertions, 14 deletions
diff --git a/tools/gpu/gl/command_buffer/GLTestContext_command_buffer.cpp b/tools/gpu/gl/command_buffer/GLTestContext_command_buffer.cpp index 54845fc28b..18e150611a 100644 --- a/tools/gpu/gl/command_buffer/GLTestContext_command_buffer.cpp +++ b/tools/gpu/gl/command_buffer/GLTestContext_command_buffer.cpp @@ -25,6 +25,7 @@ typedef void* EGLNativeDisplayType; typedef void* EGLNativeWindowType; typedef void (*__eglMustCastToProperFunctionPointerType)(void); #define EGL_FALSE 0 +#define EGL_TRUE 1 #define EGL_OPENGL_ES2_BIT 0x0004 #define EGL_CONTEXT_CLIENT_VERSION 0x3098 #define EGL_NO_SURFACE ((EGLSurface)0) @@ -45,6 +46,8 @@ typedef void (*__eglMustCastToProperFunctionPointerType)(void); #define EGL_NONE 0x3038 #define EGL_WIDTH 0x3057 #define EGL_HEIGHT 0x3056 +#define EGL_DRAW 0x3059 +#define EGL_READ 0x305A typedef EGLDisplay (*GetDisplayProc)(EGLNativeDisplayType display_id); typedef EGLBoolean (*InitializeProc)(EGLDisplay dpy, EGLint *major, EGLint *minor); @@ -77,6 +80,37 @@ static GetProcAddressProc gfGetProcAddress = nullptr; static void* gLibrary = nullptr; static bool gfFunctionsLoadedSuccessfully = false; +// The command buffer does not correctly implement eglGetCurrent. It always returns EGL_NO_<foo>. +// So we implement them ourselves and hook eglMakeCurrent to store the current values in TLS. +thread_local EGLDisplay gCurrDisplay = EGL_NO_DISPLAY; +thread_local EGLSurface gCurrReadSurface = EGL_NO_SURFACE; +thread_local EGLSurface gCurrDrawSurface = EGL_NO_SURFACE; +thread_local EGLContext gCurrContext = EGL_NO_CONTEXT; + +EGLDisplay fakeGetCurrentDisplay() { return gCurrDisplay; } +EGLSurface fakeGetCurrentSurface(EGLint readdraw) { + switch (readdraw) { + case EGL_DRAW: + return gCurrDrawSurface; + case EGL_READ: + return gCurrReadSurface; + default: + return EGL_NO_SURFACE; + } +} +EGLContext fakeGetCurrentContext() { return gCurrContext; } + +EGLBoolean hookedMakeCurrent(EGLDisplay display, EGLSurface draw, EGLSurface read, EGLContext ctx) { + if (gfFunctionsLoadedSuccessfully && EGL_TRUE == gfMakeCurrent(display, draw, read, ctx)) { + gCurrDisplay = display; + gCurrDrawSurface = draw; + gCurrReadSurface = read; + gCurrContext = ctx; + return EGL_TRUE; + } + return EGL_FALSE; +} + namespace { static void load_command_buffer_functions() { if (!gLibrary) { @@ -104,12 +138,11 @@ static void load_command_buffer_functions() { gfSwapBuffers = (SwapBuffersProc)GetProcedureAddress(gLibrary, "eglSwapBuffers"); gfGetProcAddress = (GetProcAddressProc)GetProcedureAddress(gLibrary, "eglGetProcAddress"); - gfFunctionsLoadedSuccessfully = gfGetDisplay && gfInitialize && gfTerminate && - gfChooseConfig && gfCreateWindowSurface && - gfCreatePbufferSurface && gfDestroySurface && - gfCreateContext && gfDestroyContext && gfMakeCurrent && - gfSwapBuffers && gfGetProcAddress; - + gfFunctionsLoadedSuccessfully = + gfGetDisplay && gfInitialize && gfTerminate && gfChooseConfig && + gfCreateWindowSurface && gfCreatePbufferSurface && gfDestroySurface && + gfCreateContext && gfDestroyContext && gfMakeCurrent && gfSwapBuffers && + gfGetProcAddress; } } } @@ -134,6 +167,19 @@ static const GrGLInterface* create_command_buffer_interface() { return GrGLAssembleGLESInterface(gLibrary, command_buffer_get_gl_proc); } +std::function<void()> context_restorer() { + if (!gfFunctionsLoadedSuccessfully) { + return nullptr; + } + auto display = fakeGetCurrentDisplay(); + auto dsurface = fakeGetCurrentSurface(EGL_DRAW); + auto rsurface = fakeGetCurrentSurface(EGL_READ); + auto context = fakeGetCurrentContext(); + return [display, dsurface, rsurface, context] { + hookedMakeCurrent(display, dsurface, rsurface, context); + }; +} + } // anonymous namespace namespace sk_gpu_test { @@ -204,7 +250,8 @@ CommandBufferGLTestContext::CommandBufferGLTestContext(CommandBufferGLTestContex return; } - if (!gfMakeCurrent(fDisplay, fSurface, fSurface, fContext)) { + SkScopeExit restorer(context_restorer()); + if (!hookedMakeCurrent(fDisplay, fSurface, fSurface, fContext)) { SkDebugf("Command Buffer: Could not make EGL context current.\n"); this->destroyGLContext(); return; @@ -237,15 +284,19 @@ void CommandBufferGLTestContext::destroyGLContext() { if (EGL_NO_DISPLAY == fDisplay) { return; } + bool wasCurrent = false; if (EGL_NO_CONTEXT != fContext) { + wasCurrent = fakeGetCurrentContext() == fContext; gfDestroyContext(fDisplay, fContext); fContext = EGL_NO_CONTEXT; } - // Call MakeCurrent after destroying the context, so that the EGL implementation knows that - // the context is not used anymore after it is released from being current. This way - // command buffer does not need to abandon the context before destruction, and no - // client-side errors are printed. - gfMakeCurrent(fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (wasCurrent) { + // Call MakeCurrent after destroying the context, so that the EGL implementation knows that + // the context is not used anymore after it is released from being current.This way the + // command buffer does not need to abandon the context before destruction, and no + // client-side errors are printed. + hookedMakeCurrent(fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + } if (EGL_NO_SURFACE != fSurface) { gfDestroySurface(fDisplay, fSurface); @@ -258,11 +309,18 @@ void CommandBufferGLTestContext::onPlatformMakeCurrent() const { if (!gfFunctionsLoadedSuccessfully) { return; } - if (!gfMakeCurrent(fDisplay, fSurface, fSurface, fContext)) { + if (!hookedMakeCurrent(fDisplay, fSurface, fSurface, fContext)) { SkDebugf("Command Buffer: Could not make EGL context current.\n"); } } +std::function<void()> CommandBufferGLTestContext::onPlatformGetAutoContextRestore() const { + if (!gfFunctionsLoadedSuccessfully || fakeGetCurrentContext() == fContext) { + return nullptr; + } + return context_restorer(); +} + void CommandBufferGLTestContext::onPlatformSwapBuffers() const { if (!gfFunctionsLoadedSuccessfully) { return; @@ -288,7 +346,7 @@ void CommandBufferGLTestContext::presentCommandBuffer() { } bool CommandBufferGLTestContext::makeCurrent() { - return gfMakeCurrent(fDisplay, fSurface, fSurface, fContext) != EGL_FALSE; + return hookedMakeCurrent(fDisplay, fSurface, fSurface, fContext) != EGL_FALSE; } int CommandBufferGLTestContext::getStencilBits() { |
