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 #include "SkOnce.h"
9 #include "gl/GrGLInterface.h"
10 #include "gl/GrGLAssembleInterface.h"
11 #include "gl/command_buffer/SkCommandBufferGLContext.h"
12 #include "../ports/SkOSEnvironment.h"
13 #include "../ports/SkOSLibrary.h"
14
15 #if defined SK_BUILD_FOR_MAC
16
17 // EGL doesn't exist on the mac, so expose what we need to get the command buffer's EGL running.
18 typedef void *EGLDisplay;
19 typedef unsigned int EGLBoolean;
20 typedef void *EGLConfig;
21 typedef void *EGLSurface;
22 typedef void *EGLContext;
23 typedef int32_t EGLint;
24 typedef void* EGLNativeDisplayType;
25 typedef void* EGLNativeWindowType;
26 typedef void (*__eglMustCastToProperFunctionPointerType)(void);
27 #define EGL_FALSE 0
28 #define EGL_OPENGL_ES2_BIT 0x0004
29 #define EGL_CONTEXT_CLIENT_VERSION 0x3098
30 #define EGL_NO_SURFACE ((EGLSurface)0)
31 #define EGL_NO_DISPLAY ((EGLDisplay)0)
32 #define EGL_NO_CONTEXT ((EGLContext)0)
33 #define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0)
34 #define EGL_SURFACE_TYPE 0x3033
35 #define EGL_PBUFFER_BIT 0x0001
36 #define EGL_WINDOW_BIT 0x0004
37 #define EGL_RENDERABLE_TYPE 0x3040
38 #define EGL_RED_SIZE 0x3024
39 #define EGL_GREEN_SIZE 0x3023
40 #define EGL_BLUE_SIZE 0x3022
41 #define EGL_ALPHA_SIZE 0x3021
42 #define EGL_DEPTH_SIZE 0x3025
43 #define EGL_STENCIL_SIZE 0x3025
44 #define EGL_SAMPLES 0x3031
45 #define EGL_SAMPLE_BUFFERS 0x3032
46 #define EGL_NONE 0x3038
47 #define EGL_WIDTH 0x3057
48 #define EGL_HEIGHT 0x3056
49
50 #else
51
52 #include <EGL/egl.h>
53
54 #endif
55
56 #ifndef EGL_OPENGL_ES3_BIT
57 // Part of EGL 1.5, typical headers are 1.4.
58 #define EGL_OPENGL_ES3_BIT 0x0040
59 #endif
60
61 typedef EGLDisplay (*GetDisplayProc)(EGLNativeDisplayType display_id);
62 typedef EGLBoolean (*InitializeProc)(EGLDisplay dpy, EGLint *major, EGLint *minor);
63 typedef EGLBoolean (*TerminateProc)(EGLDisplay dpy);
64 typedef EGLBoolean (*ChooseConfigProc)(EGLDisplay dpy, const EGLint* attrib_list, EGLConfig* configs, EGLint config_size, EGLint* num_config);
65 typedef EGLBoolean (*GetConfigAttrib)(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint* value);
66 typedef EGLSurface (*CreateWindowSurfaceProc)(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint* attrib_list);
67 typedef EGLSurface (*CreatePbufferSurfaceProc)(EGLDisplay dpy, EGLConfig config, const EGLint* attrib_list);
68 typedef EGLBoolean (*DestroySurfaceProc)(EGLDisplay dpy, EGLSurface surface);
69 typedef EGLContext (*CreateContextProc)(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint* attrib_list);
70 typedef EGLBoolean (*DestroyContextProc)(EGLDisplay dpy, EGLContext ctx);
71 typedef EGLBoolean (*MakeCurrentProc)(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
72 typedef EGLBoolean (*SwapBuffersProc)(EGLDisplay dpy, EGLSurface surface);
73 typedef __eglMustCastToProperFunctionPointerType (*GetProcAddressProc)(const char* procname);
74
75 static GetDisplayProc gfGetDisplay = nullptr;
76 static InitializeProc gfInitialize = nullptr;
77 static TerminateProc gfTerminate = nullptr;
78 static ChooseConfigProc gfChooseConfig = nullptr;
79 static GetConfigAttrib gfGetConfigAttrib = nullptr;
80 static CreateWindowSurfaceProc gfCreateWindowSurface = nullptr;
81 static CreatePbufferSurfaceProc gfCreatePbufferSurface = nullptr;
82 static DestroySurfaceProc gfDestroySurface = nullptr;
83 static CreateContextProc gfCreateContext = nullptr;
84 static DestroyContextProc gfDestroyContext = nullptr;
85 static MakeCurrentProc gfMakeCurrent = nullptr;
86 static SwapBuffersProc gfSwapBuffers = nullptr;
87 static GetProcAddressProc gfGetProcAddress = nullptr;
88
89 static void* gLibrary = nullptr;
90 static bool gfFunctionsLoadedSuccessfully = false;
91
load_command_buffer_functions()92 static void load_command_buffer_functions() {
93 if (!gLibrary) {
94 #if defined _WIN32
95 gLibrary = DynamicLoadLibrary("command_buffer_gles2.dll");
96 #elif defined SK_BUILD_FOR_MAC
97 gLibrary = DynamicLoadLibrary("libcommand_buffer_gles2.dylib");
98 #else
99 gLibrary = DynamicLoadLibrary("libcommand_buffer_gles2.so");
100 #endif // defined _WIN32
101 if (gLibrary) {
102 gfGetDisplay = (GetDisplayProc)GetProcedureAddress(gLibrary, "eglGetDisplay");
103 gfInitialize = (InitializeProc)GetProcedureAddress(gLibrary, "eglInitialize");
104 gfTerminate = (TerminateProc)GetProcedureAddress(gLibrary, "eglTerminate");
105 gfChooseConfig = (ChooseConfigProc)GetProcedureAddress(gLibrary, "eglChooseConfig");
106 gfGetConfigAttrib = (GetConfigAttrib)GetProcedureAddress(gLibrary, "eglGetConfigAttrib");
107 gfCreateWindowSurface = (CreateWindowSurfaceProc)GetProcedureAddress(gLibrary, "eglCreateWindowSurface");
108 gfCreatePbufferSurface = (CreatePbufferSurfaceProc)GetProcedureAddress(gLibrary, "eglCreatePbufferSurface");
109 gfDestroySurface = (DestroySurfaceProc)GetProcedureAddress(gLibrary, "eglDestroySurface");
110 gfCreateContext = (CreateContextProc)GetProcedureAddress(gLibrary, "eglCreateContext");
111 gfDestroyContext = (DestroyContextProc)GetProcedureAddress(gLibrary, "eglDestroyContext");
112 gfMakeCurrent = (MakeCurrentProc)GetProcedureAddress(gLibrary, "eglMakeCurrent");
113 gfSwapBuffers = (SwapBuffersProc)GetProcedureAddress(gLibrary, "eglSwapBuffers");
114 gfGetProcAddress = (GetProcAddressProc)GetProcedureAddress(gLibrary, "eglGetProcAddress");
115
116 gfFunctionsLoadedSuccessfully = gfGetDisplay && gfInitialize && gfTerminate &&
117 gfChooseConfig && gfCreateWindowSurface &&
118 gfCreatePbufferSurface && gfDestroySurface &&
119 gfCreateContext && gfDestroyContext && gfMakeCurrent &&
120 gfSwapBuffers && gfGetProcAddress;
121
122 }
123 }
124 }
125
command_buffer_get_gl_proc(void * ctx,const char name[])126 static GrGLFuncPtr command_buffer_get_gl_proc(void* ctx, const char name[]) {
127 if (!gfFunctionsLoadedSuccessfully) {
128 return nullptr;
129 }
130 return gfGetProcAddress(name);
131 }
132
133 SK_DECLARE_STATIC_ONCE(loadCommandBufferOnce);
LoadCommandBufferOnce()134 void LoadCommandBufferOnce() {
135 SkOnce(&loadCommandBufferOnce, load_command_buffer_functions);
136 }
137
GrGLCreateCommandBufferInterface()138 const GrGLInterface* GrGLCreateCommandBufferInterface() {
139 LoadCommandBufferOnce();
140 if (!gfFunctionsLoadedSuccessfully) {
141 return nullptr;
142 }
143 return GrGLAssembleGLESInterface(gLibrary, command_buffer_get_gl_proc);
144 }
145
SkCommandBufferGLContext(ContextVersion minContextVersion)146 SkCommandBufferGLContext::SkCommandBufferGLContext(ContextVersion minContextVersion)
147 : fContext(EGL_NO_CONTEXT)
148 , fDisplay(EGL_NO_DISPLAY)
149 , fSurface(EGL_NO_SURFACE) {
150
151 static const EGLint configAttribs[] = {
152 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
153 EGL_RENDERABLE_TYPE, minContextVersion == kGLES3_ContextVersion ? EGL_OPENGL_ES3_BIT
154 : EGL_OPENGL_ES2_BIT,
155 EGL_RED_SIZE, 8,
156 EGL_GREEN_SIZE, 8,
157 EGL_BLUE_SIZE, 8,
158 EGL_ALPHA_SIZE, 8,
159 EGL_NONE
160 };
161
162 static const EGLint surfaceAttribs[] = {
163 EGL_WIDTH, 1,
164 EGL_HEIGHT, 1,
165 EGL_NONE
166 };
167
168 initializeGLContext(minContextVersion, nullptr, configAttribs, surfaceAttribs);
169 }
170
SkCommandBufferGLContext(void * nativeWindow,int msaaSampleCount)171 SkCommandBufferGLContext::SkCommandBufferGLContext(void* nativeWindow, int msaaSampleCount) {
172 static const EGLint surfaceAttribs[] = { EGL_NONE };
173
174 EGLint configAttribs[] = {
175 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
176 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
177 EGL_RED_SIZE, 8,
178 EGL_GREEN_SIZE, 8,
179 EGL_BLUE_SIZE, 8,
180 EGL_ALPHA_SIZE, 8,
181 EGL_DEPTH_SIZE, 8,
182 EGL_STENCIL_SIZE, 8,
183 EGL_SAMPLE_BUFFERS, 1,
184 EGL_SAMPLES, msaaSampleCount,
185 EGL_NONE
186 };
187 if (msaaSampleCount == 0) {
188 configAttribs[12] = EGL_NONE;
189 }
190
191 initializeGLContext(kGLES2_ContextVersion, nativeWindow, configAttribs, surfaceAttribs);
192 }
193
initializeGLContext(ContextVersion minContextVersion,void * nativeWindow,const int * configAttribs,const int * surfaceAttribs)194 void SkCommandBufferGLContext::initializeGLContext(ContextVersion minContextVersion,
195 void* nativeWindow, const int* configAttribs,
196 const int* surfaceAttribs) {
197 LoadCommandBufferOnce();
198 if (!gfFunctionsLoadedSuccessfully) {
199 SkDebugf("Command Buffer: Could not load EGL functions.\n");
200 return;
201 }
202
203 // Make sure CHROMIUM_path_rendering is enabled for NVPR support.
204 sk_setenv("CHROME_COMMAND_BUFFER_GLES2_ARGS", "--enable-gl-path-rendering --enable-unsafe-es3-apis");
205 fDisplay = gfGetDisplay(EGL_DEFAULT_DISPLAY);
206 if (EGL_NO_DISPLAY == fDisplay) {
207 SkDebugf("Command Buffer: Could not create EGL display.\n");
208 return;
209 }
210
211 if (!gfInitialize(fDisplay, nullptr, nullptr)) {
212 SkDebugf("Command Buffer: Could not initialize EGL display.\n");
213 this->destroyGLContext();
214 return;
215 }
216
217 EGLint numConfigs;
218 if (!gfChooseConfig(fDisplay, configAttribs, static_cast<EGLConfig*>(&fConfig), 1,
219 &numConfigs) || numConfigs < 1) {
220 SkDebugf("Command Buffer: Could not choose EGL config.\n");
221 this->destroyGLContext();
222 return;
223 }
224
225 if (nativeWindow) {
226 fSurface = gfCreateWindowSurface(fDisplay,
227 static_cast<EGLConfig>(fConfig),
228 (EGLNativeWindowType)nativeWindow,
229 surfaceAttribs);
230 } else {
231 fSurface = gfCreatePbufferSurface(fDisplay,
232 static_cast<EGLConfig>(fConfig),
233 surfaceAttribs);
234 }
235 if (EGL_NO_SURFACE == fSurface) {
236 SkDebugf("Command Buffer: Could not create EGL surface.\n");
237 this->destroyGLContext();
238 return;
239 }
240
241 static const EGLint contextAttribs[] = {
242 EGL_CONTEXT_CLIENT_VERSION, minContextVersion == kGLES3_ContextVersion ? 3 : 2,
243 EGL_NONE
244 };
245 fContext = gfCreateContext(fDisplay, static_cast<EGLConfig>(fConfig), nullptr, contextAttribs);
246 if (EGL_NO_CONTEXT == fContext) {
247 SkDebugf("Command Buffer: Could not create EGL context.\n");
248 this->destroyGLContext();
249 return;
250 }
251
252 if (!gfMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
253 SkDebugf("Command Buffer: Could not make EGL context current.\n");
254 this->destroyGLContext();
255 return;
256 }
257
258 SkAutoTUnref<const GrGLInterface> gl(GrGLCreateCommandBufferInterface());
259 if (nullptr == gl.get()) {
260 SkDebugf("Command Buffer: Could not create CommandBuffer GL interface.\n");
261 this->destroyGLContext();
262 return;
263 }
264 if (!gl->validate()) {
265 SkDebugf("Command Buffer: Could not validate CommandBuffer GL interface.\n");
266 this->destroyGLContext();
267 return;
268 }
269
270 this->init(gl.detach());
271 }
272
~SkCommandBufferGLContext()273 SkCommandBufferGLContext::~SkCommandBufferGLContext() {
274 this->teardown();
275 this->destroyGLContext();
276 }
277
destroyGLContext()278 void SkCommandBufferGLContext::destroyGLContext() {
279 if (!gfFunctionsLoadedSuccessfully) {
280 return;
281 }
282 if (EGL_NO_DISPLAY == fDisplay) {
283 return;
284 }
285
286 if (EGL_NO_CONTEXT != fContext) {
287 gfDestroyContext(fDisplay, fContext);
288 fContext = EGL_NO_CONTEXT;
289 }
290 // Call MakeCurrent after destroying the context, so that the EGL implementation knows
291 // that the context is not used anymore after it is released from being current.
292 // This way command buffer does not need to abandon the context before destruction, and no
293 // client-side errors are printed.
294 gfMakeCurrent(fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
295
296 if (EGL_NO_SURFACE != fSurface) {
297 gfDestroySurface(fDisplay, fSurface);
298 fSurface = EGL_NO_SURFACE;
299 }
300 // The display is likely to be used again for another test, do not call gfTerminate. Also,
301 // terminating could imply terminating the "host" EGL inside command buffer. This would
302 // terminate also EGL that this thread might use outside of command buffer.
303 fDisplay = EGL_NO_DISPLAY;
304 }
305
onPlatformMakeCurrent() const306 void SkCommandBufferGLContext::onPlatformMakeCurrent() const {
307 if (!gfFunctionsLoadedSuccessfully) {
308 return;
309 }
310 if (!gfMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
311 SkDebugf("Command Buffer: Could not make EGL context current.\n");
312 }
313 }
314
onPlatformSwapBuffers() const315 void SkCommandBufferGLContext::onPlatformSwapBuffers() const {
316 if (!gfFunctionsLoadedSuccessfully) {
317 return;
318 }
319 if (!gfSwapBuffers(fDisplay, fSurface)) {
320 SkDebugf("Command Buffer: Could not complete gfSwapBuffers.\n");
321 }
322 }
323
onPlatformGetProcAddress(const char * name) const324 GrGLFuncPtr SkCommandBufferGLContext::onPlatformGetProcAddress(const char* name) const {
325 if (!gfFunctionsLoadedSuccessfully) {
326 return nullptr;
327 }
328 return gfGetProcAddress(name);
329 }
330
presentCommandBuffer()331 void SkCommandBufferGLContext::presentCommandBuffer() {
332 if (this->gl()) {
333 this->gl()->fFunctions.fFlush();
334 }
335
336 this->onPlatformSwapBuffers();
337 }
338
makeCurrent()339 bool SkCommandBufferGLContext::makeCurrent() {
340 return gfMakeCurrent(fDisplay, fSurface, fSurface, fContext) != EGL_FALSE;
341 }
342
getStencilBits()343 int SkCommandBufferGLContext::getStencilBits() {
344 EGLint result = 0;
345 gfGetConfigAttrib(fDisplay, static_cast<EGLConfig>(fConfig), EGL_STENCIL_SIZE, &result);
346 return result;
347 }
348
getSampleCount()349 int SkCommandBufferGLContext::getSampleCount() {
350 EGLint result = 0;
351 gfGetConfigAttrib(fDisplay, static_cast<EGLConfig>(fConfig), EGL_SAMPLES, &result);
352 return result;
353 }
354