aboutsummaryrefslogtreecommitdiff
path: root/tools/gpu/gl/command_buffer/GLTestContext_command_buffer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/gpu/gl/command_buffer/GLTestContext_command_buffer.cpp')
-rw-r--r--tools/gpu/gl/command_buffer/GLTestContext_command_buffer.cpp120
1 files changed, 105 insertions, 15 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..be2b6ad5e6 100644
--- a/tools/gpu/gl/command_buffer/GLTestContext_command_buffer.cpp
+++ b/tools/gpu/gl/command_buffer/GLTestContext_command_buffer.cpp
@@ -10,11 +10,14 @@
#include "SkMutex.h"
#include "SkOnce.h"
+#include "SkTLS.h"
#include "gl/GrGLInterface.h"
#include "gl/GrGLAssembleInterface.h"
#include "gl/command_buffer/GLTestContext_command_buffer.h"
#include "../ports/SkOSLibrary.h"
+namespace {
+
typedef void *EGLDisplay;
typedef unsigned int EGLBoolean;
typedef void *EGLConfig;
@@ -25,6 +28,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 +49,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,7 +83,6 @@ static GetProcAddressProc gfGetProcAddress = nullptr;
static void* gLibrary = nullptr;
static bool gfFunctionsLoadedSuccessfully = false;
-namespace {
static void load_command_buffer_functions() {
if (!gLibrary) {
static constexpr const char* libName =
@@ -104,12 +109,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 +138,80 @@ static const GrGLInterface* create_command_buffer_interface() {
return GrGLAssembleGLESInterface(gLibrary, command_buffer_get_gl_proc);
}
+
+// 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.
+class TLSCurrentObjects {
+public:
+ static EGLDisplay CurrentDisplay() {
+ if (auto objects = Get()) {
+ return objects->fDisplay;
+ }
+ return EGL_NO_DISPLAY;
+ }
+
+ static EGLSurface CurrentSurface(EGLint readdraw) {
+ if (auto objects = Get()) {
+ switch (readdraw) {
+ case EGL_DRAW:
+ return objects->fDrawSurface;
+ case EGL_READ:
+ return objects->fReadSurface;
+ default:
+ return EGL_NO_SURFACE;
+ }
+ }
+ return EGL_NO_SURFACE;
+ }
+
+ static EGLContext CurrentContext() {
+ if (auto objects = Get()) {
+ return objects->fContext;
+ }
+ return EGL_NO_CONTEXT;
+ }
+
+ static EGLBoolean MakeCurrent(EGLDisplay display, EGLSurface draw, EGLSurface read,
+ EGLContext ctx) {
+ if (gfFunctionsLoadedSuccessfully && EGL_TRUE == gfMakeCurrent(display, draw, read, ctx)) {
+ if (auto objects = Get()) {
+ objects->fDisplay = display;
+ objects->fDrawSurface = draw;
+ objects->fReadSurface = read;
+ objects->fContext = ctx;
+ }
+ return EGL_TRUE;
+ }
+ return EGL_FALSE;
+
+ }
+
+private:
+ EGLDisplay fDisplay = EGL_NO_DISPLAY;
+ EGLSurface fReadSurface = EGL_NO_SURFACE;
+ EGLSurface fDrawSurface = EGL_NO_SURFACE;
+ EGLContext fContext = EGL_NO_CONTEXT;
+
+ static TLSCurrentObjects* Get() {
+ return (TLSCurrentObjects*) SkTLS::Get(TLSCreate, TLSDelete);
+ }
+ static void* TLSCreate() { return new TLSCurrentObjects(); }
+ static void TLSDelete(void* objs) { delete (TLSCurrentObjects*)objs; }
+};
+
+std::function<void()> context_restorer() {
+ if (!gfFunctionsLoadedSuccessfully) {
+ return nullptr;
+ }
+ auto display = TLSCurrentObjects::CurrentDisplay();
+ auto dsurface = TLSCurrentObjects::CurrentSurface(EGL_DRAW);
+ auto rsurface = TLSCurrentObjects::CurrentSurface(EGL_READ);
+ auto context = TLSCurrentObjects::CurrentContext();
+ return [display, dsurface, rsurface, context] {
+ TLSCurrentObjects::MakeCurrent(display, dsurface, rsurface, context);
+ };
+}
+
} // anonymous namespace
namespace sk_gpu_test {
@@ -204,7 +282,8 @@ CommandBufferGLTestContext::CommandBufferGLTestContext(CommandBufferGLTestContex
return;
}
- if (!gfMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
+ SkScopeExit restorer(context_restorer());
+ if (!TLSCurrentObjects::MakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
SkDebugf("Command Buffer: Could not make EGL context current.\n");
this->destroyGLContext();
return;
@@ -237,15 +316,19 @@ void CommandBufferGLTestContext::destroyGLContext() {
if (EGL_NO_DISPLAY == fDisplay) {
return;
}
+ bool wasCurrent = false;
if (EGL_NO_CONTEXT != fContext) {
+ wasCurrent = (TLSCurrentObjects::CurrentContext() == 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.
+ TLSCurrentObjects::MakeCurrent(fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ }
if (EGL_NO_SURFACE != fSurface) {
gfDestroySurface(fDisplay, fSurface);
@@ -258,11 +341,18 @@ void CommandBufferGLTestContext::onPlatformMakeCurrent() const {
if (!gfFunctionsLoadedSuccessfully) {
return;
}
- if (!gfMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
+ if (!TLSCurrentObjects::MakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
SkDebugf("Command Buffer: Could not make EGL context current.\n");
}
}
+std::function<void()> CommandBufferGLTestContext::onPlatformGetAutoContextRestore() const {
+ if (!gfFunctionsLoadedSuccessfully || TLSCurrentObjects::CurrentContext() == fContext) {
+ return nullptr;
+ }
+ return context_restorer();
+}
+
void CommandBufferGLTestContext::onPlatformSwapBuffers() const {
if (!gfFunctionsLoadedSuccessfully) {
return;
@@ -288,7 +378,7 @@ void CommandBufferGLTestContext::presentCommandBuffer() {
}
bool CommandBufferGLTestContext::makeCurrent() {
- return gfMakeCurrent(fDisplay, fSurface, fSurface, fContext) != EGL_FALSE;
+ return TLSCurrentObjects::MakeCurrent(fDisplay, fSurface, fSurface, fContext) != EGL_FALSE;
}
int CommandBufferGLTestContext::getStencilBits() {