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 using sk_gpu_test::ANGLEBackend;
30 using sk_gpu_test::ANGLEContextVersion;
31
32 namespace {
33 struct Libs {
34 void* fGLLib;
35 void* fEGLLib;
36 };
37
angle_get_gl_proc(void * ctx,const char name[])38 static GrGLFuncPtr angle_get_gl_proc(void* ctx, const char name[]) {
39 const Libs* libs = reinterpret_cast<const Libs*>(ctx);
40 GrGLFuncPtr proc = (GrGLFuncPtr) GetProcedureAddress(libs->fGLLib, name);
41 if (proc) {
42 return proc;
43 }
44 proc = (GrGLFuncPtr) GetProcedureAddress(libs->fEGLLib, name);
45 if (proc) {
46 return proc;
47 }
48 return eglGetProcAddress(name);
49 }
50
get_angle_egl_display(void * nativeDisplay,ANGLEBackend type)51 void* get_angle_egl_display(void* nativeDisplay, ANGLEBackend type) {
52 PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT;
53 eglGetPlatformDisplayEXT =
54 (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT");
55
56 // We expect ANGLE to support this extension
57 if (!eglGetPlatformDisplayEXT) {
58 return EGL_NO_DISPLAY;
59 }
60
61 EGLint typeNum = 0;
62 switch (type) {
63 case ANGLEBackend::kD3D9:
64 typeNum = EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE;
65 break;
66 case ANGLEBackend::kD3D11:
67 typeNum = EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE;
68 break;
69 case ANGLEBackend::kOpenGL:
70 typeNum = EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE;
71 break;
72 }
73 const EGLint attribs[] = { EGL_PLATFORM_ANGLE_TYPE_ANGLE, typeNum, EGL_NONE };
74 return eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, nativeDisplay, attribs);
75 }
76
77 class ANGLEGLContext : public sk_gpu_test::GLTestContext {
78 public:
79 ANGLEGLContext(ANGLEBackend, ANGLEContextVersion, ANGLEGLContext* shareContext);
80 ~ANGLEGLContext() override;
81
82 GrEGLImage texture2DToEGLImage(GrGLuint texID) const override;
83 void destroyEGLImage(GrEGLImage) const override;
84 GrGLuint eglImageToExternalTexture(GrEGLImage) const override;
85 std::unique_ptr<sk_gpu_test::GLTestContext> makeNew() const override;
86
87 private:
88 void destroyGLContext();
89
90 void onPlatformMakeCurrent() const override;
91 void onPlatformSwapBuffers() const override;
92 GrGLFuncPtr onPlatformGetProcAddress(const char* name) const override;
93
94 void* fContext;
95 void* fDisplay;
96 void* fSurface;
97 ANGLEBackend fType;
98 ANGLEContextVersion fVersion;
99 };
100
ANGLEGLContext(ANGLEBackend type,ANGLEContextVersion version,ANGLEGLContext * shareContext)101 ANGLEGLContext::ANGLEGLContext(ANGLEBackend type, ANGLEContextVersion version,
102 ANGLEGLContext* shareContext)
103 : fContext(EGL_NO_CONTEXT)
104 , fDisplay(EGL_NO_DISPLAY)
105 , fSurface(EGL_NO_SURFACE)
106 , fType(type)
107 , fVersion(version) {
108
109 EGLint numConfigs;
110 static const EGLint configAttribs[] = {
111 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
112 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
113 EGL_RED_SIZE, 8,
114 EGL_GREEN_SIZE, 8,
115 EGL_BLUE_SIZE, 8,
116 EGL_ALPHA_SIZE, 8,
117 EGL_NONE
118 };
119
120 fDisplay = get_angle_egl_display(EGL_DEFAULT_DISPLAY, type);
121 if (EGL_NO_DISPLAY == fDisplay) {
122 SkDebugf("Could not create EGL display!");
123 return;
124 }
125
126 EGLint majorVersion;
127 EGLint minorVersion;
128 eglInitialize(fDisplay, &majorVersion, &minorVersion);
129
130 EGLConfig surfaceConfig;
131 eglChooseConfig(fDisplay, configAttribs, &surfaceConfig, 1, &numConfigs);
132
133 int versionNum = ANGLEContextVersion::kES2 == version ? 2 : 3;
134 const EGLint contextAttribs[] = {
135 EGL_CONTEXT_CLIENT_VERSION, versionNum,
136 EGL_NONE
137 };
138 EGLContext eglShareContext = shareContext ? shareContext->fContext : nullptr;
139 fContext = eglCreateContext(fDisplay, surfaceConfig, eglShareContext, contextAttribs);
140
141
142 static const EGLint surfaceAttribs[] = {
143 EGL_WIDTH, 1,
144 EGL_HEIGHT, 1,
145 EGL_NONE
146 };
147
148 fSurface = eglCreatePbufferSurface(fDisplay, surfaceConfig, surfaceAttribs);
149
150 eglMakeCurrent(fDisplay, fSurface, fSurface, fContext);
151
152 sk_sp<const GrGLInterface> gl(sk_gpu_test::CreateANGLEGLInterface());
153 if (nullptr == gl.get()) {
154 SkDebugf("Could not create ANGLE GL interface!\n");
155 this->destroyGLContext();
156 return;
157 }
158 if (!gl->validate()) {
159 SkDebugf("Could not validate ANGLE GL interface!\n");
160 this->destroyGLContext();
161 return;
162 }
163
164 this->init(gl.release());
165 }
166
~ANGLEGLContext()167 ANGLEGLContext::~ANGLEGLContext() {
168 this->teardown();
169 this->destroyGLContext();
170 }
171
texture2DToEGLImage(GrGLuint texID) const172 GrEGLImage ANGLEGLContext::texture2DToEGLImage(GrGLuint texID) const {
173 if (!this->gl()->hasExtension("EGL_KHR_gl_texture_2D_image")) {
174 return GR_EGL_NO_IMAGE;
175 }
176 GrEGLImage img;
177 GrEGLint attribs[] = { GR_EGL_GL_TEXTURE_LEVEL, 0,
178 GR_EGL_IMAGE_PRESERVED, GR_EGL_TRUE,
179 GR_EGL_NONE };
180 // 64 bit cast is to shut Visual C++ up about casting 32 bit value to a pointer.
181 GrEGLClientBuffer clientBuffer = reinterpret_cast<GrEGLClientBuffer>((uint64_t)texID);
182 GR_GL_CALL_RET(this->gl(), img,
183 EGLCreateImage(fDisplay, fContext, GR_EGL_GL_TEXTURE_2D, clientBuffer,
184 attribs));
185 return img;
186 }
187
destroyEGLImage(GrEGLImage image) const188 void ANGLEGLContext::destroyEGLImage(GrEGLImage image) const {
189 GR_GL_CALL(this->gl(), EGLDestroyImage(fDisplay, image));
190 }
191
eglImageToExternalTexture(GrEGLImage image) const192 GrGLuint ANGLEGLContext::eglImageToExternalTexture(GrEGLImage image) const {
193 GrGLClearErr(this->gl());
194 if (!this->gl()->hasExtension("GL_OES_EGL_image_external")) {
195 return 0;
196 }
197 typedef GrGLvoid (EGLAPIENTRY *EGLImageTargetTexture2DProc)(GrGLenum, GrGLeglImage);
198 EGLImageTargetTexture2DProc glEGLImageTargetTexture2D =
199 (EGLImageTargetTexture2DProc)eglGetProcAddress("glEGLImageTargetTexture2DOES");
200 if (!glEGLImageTargetTexture2D) {
201 return 0;
202 }
203 GrGLuint texID;
204 GR_GL_CALL(this->gl(), GenTextures(1, &texID));
205 if (!texID) {
206 return 0;
207 }
208 GR_GL_CALL(this->gl(), BindTexture(GR_GL_TEXTURE_EXTERNAL, texID));
209 if (GR_GL_GET_ERROR(this->gl()) != GR_GL_NO_ERROR) {
210 GR_GL_CALL(this->gl(), DeleteTextures(1, &texID));
211 return 0;
212 }
213 glEGLImageTargetTexture2D(GR_GL_TEXTURE_EXTERNAL, image);
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 return texID;
219 }
220
makeNew() const221 std::unique_ptr<sk_gpu_test::GLTestContext> ANGLEGLContext::makeNew() const {
222 std::unique_ptr<sk_gpu_test::GLTestContext> ctx =
223 sk_gpu_test::MakeANGLETestContext(fType, fVersion);
224 if (ctx) {
225 ctx->makeCurrent();
226 }
227 return ctx;
228 }
229
destroyGLContext()230 void ANGLEGLContext::destroyGLContext() {
231 if (fDisplay) {
232 eglMakeCurrent(fDisplay, 0, 0, 0);
233
234 if (fContext) {
235 eglDestroyContext(fDisplay, fContext);
236 fContext = EGL_NO_CONTEXT;
237 }
238
239 if (fSurface) {
240 eglDestroySurface(fDisplay, fSurface);
241 fSurface = EGL_NO_SURFACE;
242 }
243
244 //TODO should we close the display?
245 fDisplay = EGL_NO_DISPLAY;
246 }
247 }
248
onPlatformMakeCurrent() const249 void ANGLEGLContext::onPlatformMakeCurrent() const {
250 if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
251 SkDebugf("Could not set the context.\n");
252 }
253 }
254
onPlatformSwapBuffers() const255 void ANGLEGLContext::onPlatformSwapBuffers() const {
256 if (!eglSwapBuffers(fDisplay, fSurface)) {
257 SkDebugf("Could not complete eglSwapBuffers.\n");
258 }
259 }
260
onPlatformGetProcAddress(const char * name) const261 GrGLFuncPtr ANGLEGLContext::onPlatformGetProcAddress(const char* name) const {
262 return eglGetProcAddress(name);
263 }
264 } // anonymous namespace
265
266 namespace sk_gpu_test {
CreateANGLEGLInterface()267 const GrGLInterface* CreateANGLEGLInterface() {
268 static Libs gLibs = { nullptr, nullptr };
269
270 if (nullptr == gLibs.fGLLib) {
271 // We load the ANGLE library and never let it go
272 #if defined _WIN32
273 gLibs.fGLLib = DynamicLoadLibrary("libGLESv2.dll");
274 gLibs.fEGLLib = DynamicLoadLibrary("libEGL.dll");
275 #elif defined SK_BUILD_FOR_MAC
276 gLibs.fGLLib = DynamicLoadLibrary("libGLESv2.dylib");
277 gLibs.fEGLLib = DynamicLoadLibrary("libEGL.dylib");
278 #else
279 gLibs.fGLLib = DynamicLoadLibrary("libGLESv2.so");
280 gLibs.fEGLLib = DynamicLoadLibrary("libEGL.so");
281 #endif
282 }
283
284 if (nullptr == gLibs.fGLLib || nullptr == gLibs.fEGLLib) {
285 // We can't setup the interface correctly w/o the so
286 return nullptr;
287 }
288
289 return GrGLAssembleGLESInterface(&gLibs, angle_get_gl_proc);
290 }
291
MakeANGLETestContext(ANGLEBackend type,ANGLEContextVersion version,GLTestContext * shareContext)292 std::unique_ptr<GLTestContext> MakeANGLETestContext(ANGLEBackend type, ANGLEContextVersion version,
293 GLTestContext* shareContext){
294 ANGLEGLContext* angleShareContext = reinterpret_cast<ANGLEGLContext*>(shareContext);
295 std::unique_ptr<GLTestContext> ctx(new ANGLEGLContext(type, version, angleShareContext));
296 if (!ctx->isValid()) {
297 return nullptr;
298 }
299 return ctx;
300 }
301 } // namespace sk_gpu_test
302