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