OLD | NEW |
| (Empty) |
1 | |
2 /* | |
3 * Copyright 2012 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 "GLTestContext_angle.h" | |
10 | |
11 #include <EGL/egl.h> | |
12 #include <EGL/eglext.h> | |
13 | |
14 #include "gl/GrGLDefines.h" | |
15 #include "gl/GrGLUtil.h" | |
16 | |
17 #include "gl/GrGLInterface.h" | |
18 #include "gl/GrGLAssembleInterface.h" | |
19 #include "../ports/SkOSLibrary.h" | |
20 | |
21 #include <EGL/egl.h> | |
22 | |
23 #define EGL_PLATFORM_ANGLE_ANGLE 0x3202 | |
24 #define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3203 | |
25 #define EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE 0x3207 | |
26 #define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3208 | |
27 #define EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE 0x320D | |
28 | |
29 namespace { | |
30 struct Libs { | |
31 void* fGLLib; | |
32 void* fEGLLib; | |
33 }; | |
34 | |
35 static GrGLFuncPtr angle_get_gl_proc(void* ctx, const char name[]) { | |
36 const Libs* libs = reinterpret_cast<const Libs*>(ctx); | |
37 GrGLFuncPtr proc = (GrGLFuncPtr) GetProcedureAddress(libs->fGLLib, name); | |
38 if (proc) { | |
39 return proc; | |
40 } | |
41 proc = (GrGLFuncPtr) GetProcedureAddress(libs->fEGLLib, name); | |
42 if (proc) { | |
43 return proc; | |
44 } | |
45 return eglGetProcAddress(name); | |
46 } | |
47 | |
48 void* get_angle_egl_display(void* nativeDisplay, bool useGLBackend) { | |
49 PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT; | |
50 eglGetPlatformDisplayEXT = | |
51 (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDispla
yEXT"); | |
52 | |
53 // We expect ANGLE to support this extension | |
54 if (!eglGetPlatformDisplayEXT) { | |
55 return EGL_NO_DISPLAY; | |
56 } | |
57 | |
58 EGLDisplay display = EGL_NO_DISPLAY; | |
59 if (useGLBackend) { | |
60 EGLint attribs[3] = { | |
61 EGL_PLATFORM_ANGLE_TYPE_ANGLE, | |
62 EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, | |
63 EGL_NONE | |
64 }; | |
65 display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, nativeDispl
ay, attribs); | |
66 } else { | |
67 // Try for an ANGLE D3D11 context, fall back to D3D9. | |
68 EGLint attribs[3][3] = { | |
69 { | |
70 EGL_PLATFORM_ANGLE_TYPE_ANGLE, | |
71 EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, | |
72 EGL_NONE | |
73 }, | |
74 { | |
75 EGL_PLATFORM_ANGLE_TYPE_ANGLE, | |
76 EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE, | |
77 EGL_NONE | |
78 }, | |
79 }; | |
80 for (int i = 0; i < 3 && display == EGL_NO_DISPLAY; ++i) { | |
81 display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE,nativeDi
splay, attribs[i]); | |
82 } | |
83 } | |
84 return display; | |
85 } | |
86 | |
87 class ANGLEGLContext : public sk_gpu_test::GLTestContext { | |
88 public: | |
89 ANGLEGLContext(bool preferGLBackend); | |
90 ~ANGLEGLContext() override; | |
91 | |
92 GrEGLImage texture2DToEGLImage(GrGLuint texID) const override; | |
93 void destroyEGLImage(GrEGLImage) const override; | |
94 GrGLuint eglImageToExternalTexture(GrEGLImage) const override; | |
95 sk_gpu_test::GLTestContext* createNew() const override; | |
96 | |
97 private: | |
98 void destroyGLContext(); | |
99 | |
100 void onPlatformMakeCurrent() const override; | |
101 void onPlatformSwapBuffers() const override; | |
102 GrGLFuncPtr onPlatformGetProcAddress(const char* name) const override; | |
103 | |
104 void* fContext; | |
105 void* fDisplay; | |
106 void* fSurface; | |
107 bool fIsGLBackend; | |
108 }; | |
109 | |
110 ANGLEGLContext::ANGLEGLContext(bool useGLBackend) | |
111 : fContext(EGL_NO_CONTEXT) | |
112 , fDisplay(EGL_NO_DISPLAY) | |
113 , fSurface(EGL_NO_SURFACE) { | |
114 | |
115 EGLint numConfigs; | |
116 static const EGLint configAttribs[] = { | |
117 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, | |
118 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, | |
119 EGL_RED_SIZE, 8, | |
120 EGL_GREEN_SIZE, 8, | |
121 EGL_BLUE_SIZE, 8, | |
122 EGL_ALPHA_SIZE, 8, | |
123 EGL_NONE | |
124 }; | |
125 | |
126 fIsGLBackend = useGLBackend; | |
127 fDisplay = get_angle_egl_display(EGL_DEFAULT_DISPLAY, useGLBackend); | |
128 if (EGL_NO_DISPLAY == fDisplay) { | |
129 SkDebugf("Could not create EGL display!"); | |
130 return; | |
131 } | |
132 | |
133 EGLint majorVersion; | |
134 EGLint minorVersion; | |
135 eglInitialize(fDisplay, &majorVersion, &minorVersion); | |
136 | |
137 EGLConfig surfaceConfig; | |
138 eglChooseConfig(fDisplay, configAttribs, &surfaceConfig, 1, &numConfigs); | |
139 | |
140 static const EGLint contextAttribs[] = { | |
141 EGL_CONTEXT_CLIENT_VERSION, 2, | |
142 EGL_NONE | |
143 }; | |
144 fContext = eglCreateContext(fDisplay, surfaceConfig, nullptr, contextAttribs
); | |
145 | |
146 | |
147 static const EGLint surfaceAttribs[] = { | |
148 EGL_WIDTH, 1, | |
149 EGL_HEIGHT, 1, | |
150 EGL_NONE | |
151 }; | |
152 | |
153 fSurface = eglCreatePbufferSurface(fDisplay, surfaceConfig, surfaceAttribs); | |
154 | |
155 eglMakeCurrent(fDisplay, fSurface, fSurface, fContext); | |
156 | |
157 SkAutoTUnref<const GrGLInterface> gl(sk_gpu_test::CreateANGLEGLInterface()); | |
158 if (nullptr == gl.get()) { | |
159 SkDebugf("Could not create ANGLE GL interface!\n"); | |
160 this->destroyGLContext(); | |
161 return; | |
162 } | |
163 if (!gl->validate()) { | |
164 SkDebugf("Could not validate ANGLE GL interface!\n"); | |
165 this->destroyGLContext(); | |
166 return; | |
167 } | |
168 | |
169 this->init(gl.release()); | |
170 } | |
171 | |
172 ANGLEGLContext::~ANGLEGLContext() { | |
173 this->teardown(); | |
174 this->destroyGLContext(); | |
175 } | |
176 | |
177 GrEGLImage ANGLEGLContext::texture2DToEGLImage(GrGLuint texID) const { | |
178 if (!this->gl()->hasExtension("EGL_KHR_gl_texture_2D_image")) { | |
179 return GR_EGL_NO_IMAGE; | |
180 } | |
181 GrEGLImage img; | |
182 GrEGLint attribs[] = { GR_EGL_GL_TEXTURE_LEVEL, 0, | |
183 GR_EGL_IMAGE_PRESERVED, GR_EGL_TRUE, | |
184 GR_EGL_NONE }; | |
185 // 64 bit cast is to shut Visual C++ up about casting 32 bit value to a poin
ter. | |
186 GrEGLClientBuffer clientBuffer = reinterpret_cast<GrEGLClientBuffer>((uint64
_t)texID); | |
187 GR_GL_CALL_RET(this->gl(), img, | |
188 EGLCreateImage(fDisplay, fContext, GR_EGL_GL_TEXTURE_2D, clie
ntBuffer, | |
189 attribs)); | |
190 return img; | |
191 } | |
192 | |
193 void ANGLEGLContext::destroyEGLImage(GrEGLImage image) const { | |
194 GR_GL_CALL(this->gl(), EGLDestroyImage(fDisplay, image)); | |
195 } | |
196 | |
197 GrGLuint ANGLEGLContext::eglImageToExternalTexture(GrEGLImage image) const { | |
198 GrGLClearErr(this->gl()); | |
199 if (!this->gl()->hasExtension("GL_OES_EGL_image_external")) { | |
200 return 0; | |
201 } | |
202 typedef GrGLvoid (*EGLImageTargetTexture2DProc)(GrGLenum, GrGLeglImage); | |
203 EGLImageTargetTexture2DProc glEGLImageTargetTexture2D = | |
204 (EGLImageTargetTexture2DProc)eglGetProcAddress("glEGLImageTargetTexture2
DOES"); | |
205 if (!glEGLImageTargetTexture2D) { | |
206 return 0; | |
207 } | |
208 GrGLuint texID; | |
209 GR_GL_CALL(this->gl(), GenTextures(1, &texID)); | |
210 if (!texID) { | |
211 return 0; | |
212 } | |
213 GR_GL_CALL(this->gl(), BindTexture(GR_GL_TEXTURE_EXTERNAL, texID)); | |
214 if (GR_GL_GET_ERROR(this->gl()) != GR_GL_NO_ERROR) { | |
215 GR_GL_CALL(this->gl(), DeleteTextures(1, &texID)); | |
216 return 0; | |
217 } | |
218 glEGLImageTargetTexture2D(GR_GL_TEXTURE_EXTERNAL, image); | |
219 if (GR_GL_GET_ERROR(this->gl()) != GR_GL_NO_ERROR) { | |
220 GR_GL_CALL(this->gl(), DeleteTextures(1, &texID)); | |
221 return 0; | |
222 } | |
223 return texID; | |
224 } | |
225 | |
226 sk_gpu_test::GLTestContext* ANGLEGLContext::createNew() const { | |
227 #ifdef SK_BUILD_FOR_WIN | |
228 sk_gpu_test::GLTestContext* ctx = fIsGLBackend ? sk_gpu_test::CreateANGLEOpe
nGLGLContext() | |
229 : sk_gpu_test::CreateANGLEDirect3
DGLContext(); | |
230 #else | |
231 sk_gpu_test::GLTestContext* ctx = sk_gpu_test::CreateANGLEOpenGLGLTestContex
t(); | |
232 #endif | |
233 if (ctx) { | |
234 ctx->makeCurrent(); | |
235 } | |
236 return ctx; | |
237 } | |
238 | |
239 void ANGLEGLContext::destroyGLContext() { | |
240 if (fDisplay) { | |
241 eglMakeCurrent(fDisplay, 0, 0, 0); | |
242 | |
243 if (fContext) { | |
244 eglDestroyContext(fDisplay, fContext); | |
245 fContext = EGL_NO_CONTEXT; | |
246 } | |
247 | |
248 if (fSurface) { | |
249 eglDestroySurface(fDisplay, fSurface); | |
250 fSurface = EGL_NO_SURFACE; | |
251 } | |
252 | |
253 //TODO should we close the display? | |
254 fDisplay = EGL_NO_DISPLAY; | |
255 } | |
256 } | |
257 | |
258 void ANGLEGLContext::onPlatformMakeCurrent() const { | |
259 if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) { | |
260 SkDebugf("Could not set the context.\n"); | |
261 } | |
262 } | |
263 | |
264 void ANGLEGLContext::onPlatformSwapBuffers() const { | |
265 if (!eglSwapBuffers(fDisplay, fSurface)) { | |
266 SkDebugf("Could not complete eglSwapBuffers.\n"); | |
267 } | |
268 } | |
269 | |
270 GrGLFuncPtr ANGLEGLContext::onPlatformGetProcAddress(const char* name) const { | |
271 return eglGetProcAddress(name); | |
272 } | |
273 } // anonymous namespace | |
274 | |
275 namespace sk_gpu_test { | |
276 const GrGLInterface* CreateANGLEGLInterface() { | |
277 static Libs gLibs = { nullptr, nullptr }; | |
278 | |
279 if (nullptr == gLibs.fGLLib) { | |
280 // We load the ANGLE library and never let it go | |
281 #if defined _WIN32 | |
282 gLibs.fGLLib = DynamicLoadLibrary("libGLESv2.dll"); | |
283 gLibs.fEGLLib = DynamicLoadLibrary("libEGL.dll"); | |
284 #elif defined SK_BUILD_FOR_MAC | |
285 gLibs.fGLLib = DynamicLoadLibrary("libGLESv2.dylib"); | |
286 gLibs.fEGLLib = DynamicLoadLibrary("libEGL.dylib"); | |
287 #else | |
288 gLibs.fGLLib = DynamicLoadLibrary("libGLESv2.so"); | |
289 gLibs.fEGLLib = DynamicLoadLibrary("libEGL.so"); | |
290 #endif | |
291 } | |
292 | |
293 if (nullptr == gLibs.fGLLib || nullptr == gLibs.fEGLLib) { | |
294 // We can't setup the interface correctly w/o the so | |
295 return nullptr; | |
296 } | |
297 | |
298 return GrGLAssembleGLESInterface(&gLibs, angle_get_gl_proc); | |
299 } | |
300 | |
301 #ifdef SK_BUILD_FOR_WIN | |
302 GLTestContext* CreateANGLEDirect3DGLTestContext() { | |
303 ANGLEGLContext* ctx = new ANGLEGLContext(false); | |
304 if (!ctx->isValid()) { | |
305 delete ctx; | |
306 return NULL; | |
307 } | |
308 return ctx; | |
309 } | |
310 #endif | |
311 | |
312 GLTestContext* CreateANGLEOpenGLGLTestContext() { | |
313 ANGLEGLContext* ctx = new ANGLEGLContext(true); | |
314 if (!ctx->isValid()) { | |
315 delete ctx; | |
316 return NULL; | |
317 } | |
318 return ctx; | |
319 } | |
320 } // namespace sk_gpu_test | |
OLD | NEW |