1 2/* 3 * Copyright 2015 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9#include "SkMutex.h" 10#include "SkOnce.h" 11#include "gl/GrGLInterface.h" 12#include "gl/GrGLAssembleInterface.h" 13#include "gl/command_buffer/GLTestContext_command_buffer.h" 14#include "../ports/SkOSLibrary.h" 15 16typedef void *EGLDisplay; 17typedef unsigned int EGLBoolean; 18typedef void *EGLConfig; 19typedef void *EGLSurface; 20typedef void *EGLContext; 21typedef int32_t EGLint; 22typedef void* EGLNativeDisplayType; 23typedef void* EGLNativeWindowType; 24typedef void (*__eglMustCastToProperFunctionPointerType)(void); 25#define EGL_FALSE 0 26#define EGL_OPENGL_ES2_BIT 0x0004 27#define EGL_CONTEXT_CLIENT_VERSION 0x3098 28#define EGL_NO_SURFACE ((EGLSurface)0) 29#define EGL_NO_DISPLAY ((EGLDisplay)0) 30#define EGL_NO_CONTEXT ((EGLContext)0) 31#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0) 32#define EGL_SURFACE_TYPE 0x3033 33#define EGL_PBUFFER_BIT 0x0001 34#define EGL_RENDERABLE_TYPE 0x3040 35#define EGL_RED_SIZE 0x3024 36#define EGL_GREEN_SIZE 0x3023 37#define EGL_BLUE_SIZE 0x3022 38#define EGL_ALPHA_SIZE 0x3021 39#define EGL_DEPTH_SIZE 0x3025 40#define EGL_STENCIL_SIZE 0x3025 41#define EGL_SAMPLES 0x3031 42#define EGL_SAMPLE_BUFFERS 0x3032 43#define EGL_NONE 0x3038 44#define EGL_WIDTH 0x3057 45#define EGL_HEIGHT 0x3056 46 47typedef EGLDisplay (*GetDisplayProc)(EGLNativeDisplayType display_id); 48typedef EGLBoolean (*InitializeProc)(EGLDisplay dpy, EGLint *major, EGLint *minor); 49typedef EGLBoolean (*TerminateProc)(EGLDisplay dpy); 50typedef EGLBoolean (*ChooseConfigProc)(EGLDisplay dpy, const EGLint* attrib_list, EGLConfig* configs, EGLint config_size, EGLint* num_config); 51typedef EGLBoolean (*GetConfigAttrib)(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint* value); 52typedef EGLSurface (*CreateWindowSurfaceProc)(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint* attrib_list); 53typedef EGLSurface (*CreatePbufferSurfaceProc)(EGLDisplay dpy, EGLConfig config, const EGLint* attrib_list); 54typedef EGLBoolean (*DestroySurfaceProc)(EGLDisplay dpy, EGLSurface surface); 55typedef EGLContext (*CreateContextProc)(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint* attrib_list); 56typedef EGLBoolean (*DestroyContextProc)(EGLDisplay dpy, EGLContext ctx); 57typedef EGLBoolean (*MakeCurrentProc)(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx); 58typedef EGLBoolean (*SwapBuffersProc)(EGLDisplay dpy, EGLSurface surface); 59typedef __eglMustCastToProperFunctionPointerType (*GetProcAddressProc)(const char* procname); 60 61static GetDisplayProc gfGetDisplay = nullptr; 62static InitializeProc gfInitialize = nullptr; 63static TerminateProc gfTerminate = nullptr; 64static ChooseConfigProc gfChooseConfig = nullptr; 65static GetConfigAttrib gfGetConfigAttrib = nullptr; 66static CreateWindowSurfaceProc gfCreateWindowSurface = nullptr; 67static CreatePbufferSurfaceProc gfCreatePbufferSurface = nullptr; 68static DestroySurfaceProc gfDestroySurface = nullptr; 69static CreateContextProc gfCreateContext = nullptr; 70static DestroyContextProc gfDestroyContext = nullptr; 71static MakeCurrentProc gfMakeCurrent = nullptr; 72static SwapBuffersProc gfSwapBuffers = nullptr; 73static GetProcAddressProc gfGetProcAddress = nullptr; 74 75static void* gLibrary = nullptr; 76static bool gfFunctionsLoadedSuccessfully = false; 77 78namespace { 79static void load_command_buffer_functions() { 80 if (!gLibrary) { 81 static constexpr const char* libName = 82#if defined _WIN32 83 "command_buffer_gles2.dll"; 84#elif defined SK_BUILD_FOR_MAC 85 "libcommand_buffer_gles2.dylib"; 86#else 87 "libcommand_buffer_gles2.so"; 88#endif // defined _WIN32 89 gLibrary = DynamicLoadLibrary(libName); 90 if (gLibrary) { 91 gfGetDisplay = (GetDisplayProc)GetProcedureAddress(gLibrary, "eglGetDisplay"); 92 gfInitialize = (InitializeProc)GetProcedureAddress(gLibrary, "eglInitialize"); 93 gfTerminate = (TerminateProc)GetProcedureAddress(gLibrary, "eglTerminate"); 94 gfChooseConfig = (ChooseConfigProc)GetProcedureAddress(gLibrary, "eglChooseConfig"); 95 gfGetConfigAttrib = (GetConfigAttrib)GetProcedureAddress(gLibrary, "eglGetConfigAttrib"); 96 gfCreateWindowSurface = (CreateWindowSurfaceProc)GetProcedureAddress(gLibrary, "eglCreateWindowSurface"); 97 gfCreatePbufferSurface = (CreatePbufferSurfaceProc)GetProcedureAddress(gLibrary, "eglCreatePbufferSurface"); 98 gfDestroySurface = (DestroySurfaceProc)GetProcedureAddress(gLibrary, "eglDestroySurface"); 99 gfCreateContext = (CreateContextProc)GetProcedureAddress(gLibrary, "eglCreateContext"); 100 gfDestroyContext = (DestroyContextProc)GetProcedureAddress(gLibrary, "eglDestroyContext"); 101 gfMakeCurrent = (MakeCurrentProc)GetProcedureAddress(gLibrary, "eglMakeCurrent"); 102 gfSwapBuffers = (SwapBuffersProc)GetProcedureAddress(gLibrary, "eglSwapBuffers"); 103 gfGetProcAddress = (GetProcAddressProc)GetProcedureAddress(gLibrary, "eglGetProcAddress"); 104 105 gfFunctionsLoadedSuccessfully = gfGetDisplay && gfInitialize && gfTerminate && 106 gfChooseConfig && gfCreateWindowSurface && 107 gfCreatePbufferSurface && gfDestroySurface && 108 gfCreateContext && gfDestroyContext && gfMakeCurrent && 109 gfSwapBuffers && gfGetProcAddress; 110 111 } 112 } 113} 114 115static GrGLFuncPtr command_buffer_get_gl_proc(void* ctx, const char name[]) { 116 if (!gfFunctionsLoadedSuccessfully) { 117 return nullptr; 118 } 119 return gfGetProcAddress(name); 120} 121 122static void load_command_buffer_once() { 123 static SkOnce once; 124 once(load_command_buffer_functions); 125} 126 127static const GrGLInterface* create_command_buffer_interface() { 128 load_command_buffer_once(); 129 if (!gfFunctionsLoadedSuccessfully) { 130 return nullptr; 131 } 132 return GrGLAssembleGLESInterface(gLibrary, command_buffer_get_gl_proc); 133} 134 135} // anonymous namespace 136 137namespace sk_gpu_test { 138 139CommandBufferGLTestContext::CommandBufferGLTestContext(CommandBufferGLTestContext* shareContext) 140 : fContext(EGL_NO_CONTEXT), fDisplay(EGL_NO_DISPLAY), fSurface(EGL_NO_SURFACE) { 141 142 static const EGLint configAttribs[] = { 143 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, 144 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 145 EGL_RED_SIZE, 8, 146 EGL_GREEN_SIZE, 8, 147 EGL_BLUE_SIZE, 8, 148 EGL_ALPHA_SIZE, 8, 149 EGL_NONE 150 }; 151 152 static const EGLint surfaceAttribs[] = { 153 EGL_WIDTH, 1, 154 EGL_HEIGHT, 1, 155 EGL_NONE 156 }; 157 158 load_command_buffer_once(); 159 if (!gfFunctionsLoadedSuccessfully) { 160 return; 161 } 162 163 fDisplay = gfGetDisplay(EGL_DEFAULT_DISPLAY); 164 if (EGL_NO_DISPLAY == fDisplay) { 165 SkDebugf("Command Buffer: Could not create EGL display.\n"); 166 return; 167 } 168 if (!gfInitialize(fDisplay, nullptr, nullptr)) { 169 SkDebugf("Command Buffer: Could not initialize EGL display.\n"); 170 this->destroyGLContext(); 171 return; 172 } 173 EGLint numConfigs; 174 if (!gfChooseConfig(fDisplay, configAttribs, static_cast<EGLConfig *>(&fConfig), 1, 175 &numConfigs) || numConfigs != 1) { 176 SkDebugf("Command Buffer: Could not choose EGL config.\n"); 177 this->destroyGLContext(); 178 return; 179 } 180 181 fSurface = gfCreatePbufferSurface(fDisplay, 182 static_cast<EGLConfig>(fConfig), 183 surfaceAttribs); 184 185 if (EGL_NO_SURFACE == fSurface) { 186 SkDebugf("Command Buffer: Could not create EGL surface.\n"); 187 this->destroyGLContext(); 188 return; 189 } 190 191 static const EGLint contextAttribs[] = { 192 EGL_CONTEXT_CLIENT_VERSION, 2, 193 EGL_NONE 194 }; 195 EGLContext eglShareContext = shareContext 196 ? reinterpret_cast<EGLContext>(shareContext->fContext) : nullptr; 197 fContext = gfCreateContext(fDisplay, static_cast<EGLConfig>(fConfig), eglShareContext, 198 contextAttribs); 199 if (EGL_NO_CONTEXT == fContext) { 200 SkDebugf("Command Buffer: Could not create EGL context.\n"); 201 this->destroyGLContext(); 202 return; 203 } 204 205 if (!gfMakeCurrent(fDisplay, fSurface, fSurface, fContext)) { 206 SkDebugf("Command Buffer: Could not make EGL context current.\n"); 207 this->destroyGLContext(); 208 return; 209 } 210 211 sk_sp<const GrGLInterface> gl(create_command_buffer_interface()); 212 if (nullptr == gl.get()) { 213 SkDebugf("Command Buffer: Could not create CommandBuffer GL interface.\n"); 214 this->destroyGLContext(); 215 return; 216 } 217 if (!gl->validate()) { 218 SkDebugf("Command Buffer: Could not validate CommandBuffer GL interface.\n"); 219 this->destroyGLContext(); 220 return; 221 } 222 223 this->init(gl.release()); 224} 225 226CommandBufferGLTestContext::~CommandBufferGLTestContext() { 227 this->teardown(); 228 this->destroyGLContext(); 229} 230 231void CommandBufferGLTestContext::destroyGLContext() { 232 if (!gfFunctionsLoadedSuccessfully) { 233 return; 234 } 235 if (EGL_NO_DISPLAY == fDisplay) { 236 return; 237 } 238 if (EGL_NO_CONTEXT != fContext) { 239 gfDestroyContext(fDisplay, fContext); 240 fContext = EGL_NO_CONTEXT; 241 } 242 // Call MakeCurrent after destroying the context, so that the EGL implementation knows that 243 // the context is not used anymore after it is released from being current. This way 244 // command buffer does not need to abandon the context before destruction, and no 245 // client-side errors are printed. 246 gfMakeCurrent(fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 247 248 if (EGL_NO_SURFACE != fSurface) { 249 gfDestroySurface(fDisplay, fSurface); 250 fSurface = EGL_NO_SURFACE; 251 } 252 fDisplay = EGL_NO_DISPLAY; 253} 254 255void CommandBufferGLTestContext::onPlatformMakeCurrent() const { 256 if (!gfFunctionsLoadedSuccessfully) { 257 return; 258 } 259 if (!gfMakeCurrent(fDisplay, fSurface, fSurface, fContext)) { 260 SkDebugf("Command Buffer: Could not make EGL context current.\n"); 261 } 262} 263 264void CommandBufferGLTestContext::onPlatformSwapBuffers() const { 265 if (!gfFunctionsLoadedSuccessfully) { 266 return; 267 } 268 if (!gfSwapBuffers(fDisplay, fSurface)) { 269 SkDebugf("Command Buffer: Could not complete gfSwapBuffers.\n"); 270 } 271} 272 273GrGLFuncPtr CommandBufferGLTestContext::onPlatformGetProcAddress(const char *name) const { 274 if (!gfFunctionsLoadedSuccessfully) { 275 return nullptr; 276 } 277 return gfGetProcAddress(name); 278} 279 280void CommandBufferGLTestContext::presentCommandBuffer() { 281 if (this->gl()) { 282 this->gl()->fFunctions.fFlush(); 283 } 284 285 this->onPlatformSwapBuffers(); 286} 287 288bool CommandBufferGLTestContext::makeCurrent() { 289 return gfMakeCurrent(fDisplay, fSurface, fSurface, fContext) != EGL_FALSE; 290} 291 292int CommandBufferGLTestContext::getStencilBits() { 293 EGLint result = 0; 294 gfGetConfigAttrib(fDisplay, static_cast<EGLConfig>(fConfig), EGL_STENCIL_SIZE, &result); 295 return result; 296} 297 298int CommandBufferGLTestContext::getSampleCount() { 299 EGLint result = 0; 300 gfGetConfigAttrib(fDisplay, static_cast<EGLConfig>(fConfig), EGL_SAMPLES, &result); 301 return result; 302} 303 304} // namespace sk_gpu_test 305