• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2012 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "GLTestContext_angle.h"
9 
10 #include <EGL/egl.h>
11 #include <EGL/eglext.h>
12 
13 #include "gl/GrGLDefines.h"
14 #include "gl/GrGLUtil.h"
15 
16 #include "gl/GrGLInterface.h"
17 #include "gl/GrGLAssembleInterface.h"
18 #include "../ports/SkOSLibrary.h"
19 
20 #include <EGL/egl.h>
21 
22 #define EGL_PLATFORM_ANGLE_ANGLE                0x3202
23 #define EGL_PLATFORM_ANGLE_TYPE_ANGLE           0x3203
24 #define EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE      0x3207
25 #define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE     0x3208
26 #define EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE    0x320D
27 
28 using sk_gpu_test::ANGLEBackend;
29 using sk_gpu_test::ANGLEContextVersion;
30 
31 namespace {
32 struct Libs {
33     void* fGLLib;
34     void* fEGLLib;
35 };
36 
angle_get_gl_proc(void * ctx,const char name[])37 static GrGLFuncPtr angle_get_gl_proc(void* ctx, const char name[]) {
38     const Libs* libs = reinterpret_cast<const Libs*>(ctx);
39     GrGLFuncPtr proc = (GrGLFuncPtr) GetProcedureAddress(libs->fGLLib, name);
40     if (proc) {
41         return proc;
42     }
43     proc = (GrGLFuncPtr) GetProcedureAddress(libs->fEGLLib, name);
44     if (proc) {
45         return proc;
46     }
47     return eglGetProcAddress(name);
48 }
49 
get_angle_egl_display(void * nativeDisplay,ANGLEBackend type)50 void* get_angle_egl_display(void* nativeDisplay, ANGLEBackend type) {
51     PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT;
52     eglGetPlatformDisplayEXT =
53         (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT");
54 
55     // We expect ANGLE to support this extension
56     if (!eglGetPlatformDisplayEXT) {
57         return EGL_NO_DISPLAY;
58     }
59 
60     EGLint typeNum = 0;
61     switch (type) {
62         case ANGLEBackend::kD3D9:
63             typeNum = EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE;
64             break;
65         case ANGLEBackend::kD3D11:
66             typeNum = EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE;
67             break;
68         case ANGLEBackend::kOpenGL:
69             typeNum = EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE;
70             break;
71     }
72     const EGLint attribs[] = { EGL_PLATFORM_ANGLE_TYPE_ANGLE, typeNum, EGL_NONE };
73     return eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, nativeDisplay, attribs);
74 }
75 
76 class ANGLEGLContext : public sk_gpu_test::GLTestContext {
77 public:
78     ANGLEGLContext(ANGLEBackend, ANGLEContextVersion, ANGLEGLContext* shareContext, void* display);
79     ~ANGLEGLContext() override;
80 
81     GrEGLImage texture2DToEGLImage(GrGLuint texID) const override;
82     void destroyEGLImage(GrEGLImage) const override;
83     GrGLuint eglImageToExternalTexture(GrEGLImage) const override;
84     std::unique_ptr<sk_gpu_test::GLTestContext> makeNew() const override;
85 
86 private:
87     void destroyGLContext();
88 
89     void onPlatformMakeCurrent() const override;
90     void onPlatformSwapBuffers() const override;
91     GrGLFuncPtr onPlatformGetProcAddress(const char* name) const override;
92 
93     void*                       fContext;
94     void*                       fDisplay;
95     void*                       fSurface;
96     ANGLEBackend                fType;
97     ANGLEContextVersion         fVersion;
98 
99 #ifdef SK_BUILD_FOR_WIN
100     HWND                        fWindow;
101     HDC                         fDeviceContext;
102     static ATOM                 gWC;
103 #endif
104 };
105 
106 #ifdef SK_BUILD_FOR_WIN
107 ATOM ANGLEGLContext::gWC = 0;
108 #endif
109 
ANGLEGLContext(ANGLEBackend type,ANGLEContextVersion version,ANGLEGLContext * shareContext,void * display)110 ANGLEGLContext::ANGLEGLContext(ANGLEBackend type, ANGLEContextVersion version,
111                                ANGLEGLContext* shareContext, void* display)
112     : fContext(EGL_NO_CONTEXT)
113     , fDisplay(display)
114     , fSurface(EGL_NO_SURFACE)
115     , fType(type)
116     , fVersion(version) {
117 #ifdef SK_BUILD_FOR_WIN
118     fWindow = nullptr;
119     fDeviceContext = nullptr;
120 
121     if (EGL_NO_DISPLAY == fDisplay) {
122         HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(nullptr);
123 
124         if (!gWC) {
125             WNDCLASS wc;
126             wc.cbClsExtra = 0;
127             wc.cbWndExtra = 0;
128             wc.hbrBackground = nullptr;
129             wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
130             wc.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
131             wc.hInstance = hInstance;
132             wc.lpfnWndProc = (WNDPROC) DefWindowProc;
133             wc.lpszClassName = TEXT("ANGLE-win");
134             wc.lpszMenuName = nullptr;
135             wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
136 
137             gWC = RegisterClass(&wc);
138             if (!gWC) {
139                 SkDebugf("Could not register window class.\n");
140                 return;
141             }
142         }
143         if (!(fWindow = CreateWindow(TEXT("ANGLE-win"),
144                                         TEXT("The Invisible Man"),
145                                         WS_OVERLAPPEDWINDOW,
146                                         0, 0, 1, 1,
147                                         nullptr, nullptr,
148                                         hInstance, nullptr))) {
149             SkDebugf("Could not create window.\n");
150             return;
151         }
152 
153         if (!(fDeviceContext = GetDC(fWindow))) {
154             SkDebugf("Could not get device context.\n");
155             this->destroyGLContext();
156             return;
157         }
158 
159         fDisplay = get_angle_egl_display(fDeviceContext, type);
160     }
161 #else
162     SkASSERT(EGL_NO_DISPLAY == fDisplay);
163     fDisplay = get_angle_egl_display(EGL_DEFAULT_DISPLAY, type);
164 #endif
165     if (EGL_NO_DISPLAY == fDisplay) {
166         SkDebugf("Could not create EGL display!");
167         return;
168     }
169 
170     EGLint majorVersion;
171     EGLint minorVersion;
172     if (!eglInitialize(fDisplay, &majorVersion, &minorVersion)) {
173         SkDebugf("Could not initialize display!");
174         this->destroyGLContext();
175         return;
176     }
177 
178     EGLint numConfigs;
179     static const EGLint configAttribs[] = {
180         EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
181         EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
182         EGL_RED_SIZE, 8,
183         EGL_GREEN_SIZE, 8,
184         EGL_BLUE_SIZE, 8,
185         EGL_ALPHA_SIZE, 8,
186         EGL_NONE
187     };
188 
189     EGLConfig surfaceConfig;
190     if (!eglChooseConfig(fDisplay, configAttribs, &surfaceConfig, 1, &numConfigs)) {
191         SkDebugf("Could not create choose config!");
192         this->destroyGLContext();
193         return;
194     }
195 
196     int versionNum = ANGLEContextVersion::kES2 == version ? 2 : 3;
197     const EGLint contextAttribs[] = {
198         EGL_CONTEXT_CLIENT_VERSION, versionNum,
199         EGL_NONE
200     };
201     EGLContext eglShareContext = shareContext ? shareContext->fContext : nullptr;
202     fContext = eglCreateContext(fDisplay, surfaceConfig, eglShareContext, contextAttribs);
203     if (EGL_NO_CONTEXT == fContext) {
204         SkDebugf("Could not create context!");
205         this->destroyGLContext();
206         return;
207     }
208 
209     static const EGLint surfaceAttribs[] = {
210         EGL_WIDTH, 1,
211         EGL_HEIGHT, 1,
212         EGL_NONE
213     };
214 
215     fSurface = eglCreatePbufferSurface(fDisplay, surfaceConfig, surfaceAttribs);
216 
217     if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
218         SkDebugf("Could not set the context.");
219         this->destroyGLContext();
220         return;
221     }
222 
223     sk_sp<const GrGLInterface> gl(sk_gpu_test::CreateANGLEGLInterface());
224     if (nullptr == gl.get()) {
225         SkDebugf("Could not create ANGLE GL interface!\n");
226         this->destroyGLContext();
227         return;
228     }
229     if (!gl->validate()) {
230         SkDebugf("Could not validate ANGLE GL interface!\n");
231         this->destroyGLContext();
232         return;
233     }
234 
235 #ifdef SK_DEBUG
236     // Verify that the interface we requested was actually returned to us
237     const GrGLubyte* rendererUByte;
238     GR_GL_CALL_RET(gl.get(), rendererUByte, GetString(GR_GL_RENDERER));
239     const char* renderer = reinterpret_cast<const char*>(rendererUByte);
240     switch (type) {
241     case ANGLEBackend::kD3D9:
242         SkASSERT(strstr(renderer, "Direct3D9"));
243         break;
244     case ANGLEBackend::kD3D11:
245         SkASSERT(strstr(renderer, "Direct3D11"));
246         break;
247     case ANGLEBackend::kOpenGL:
248         SkASSERT(strstr(renderer, "OpenGL"));
249         break;
250     }
251 #endif
252 
253     this->init(gl.release());
254 }
255 
~ANGLEGLContext()256 ANGLEGLContext::~ANGLEGLContext() {
257     this->teardown();
258     this->destroyGLContext();
259 }
260 
texture2DToEGLImage(GrGLuint texID) const261 GrEGLImage ANGLEGLContext::texture2DToEGLImage(GrGLuint texID) const {
262     if (!this->gl()->hasExtension("EGL_KHR_gl_texture_2D_image")) {
263         return GR_EGL_NO_IMAGE;
264     }
265     GrEGLImage img;
266     GrEGLint attribs[] = { GR_EGL_GL_TEXTURE_LEVEL, 0,
267                            GR_EGL_IMAGE_PRESERVED, GR_EGL_TRUE,
268                            GR_EGL_NONE };
269     // 64 bit cast is to shut Visual C++ up about casting 32 bit value to a pointer.
270     GrEGLClientBuffer clientBuffer = reinterpret_cast<GrEGLClientBuffer>((uint64_t)texID);
271     GR_GL_CALL_RET(this->gl(), img,
272                    EGLCreateImage(fDisplay, fContext, GR_EGL_GL_TEXTURE_2D, clientBuffer,
273                                   attribs));
274     return img;
275 }
276 
destroyEGLImage(GrEGLImage image) const277 void ANGLEGLContext::destroyEGLImage(GrEGLImage image) const {
278     GR_GL_CALL(this->gl(), EGLDestroyImage(fDisplay, image));
279 }
280 
eglImageToExternalTexture(GrEGLImage image) const281 GrGLuint ANGLEGLContext::eglImageToExternalTexture(GrEGLImage image) const {
282     GrGLClearErr(this->gl());
283     if (!this->gl()->hasExtension("GL_OES_EGL_image_external")) {
284         return 0;
285     }
286     typedef GrGLvoid (EGLAPIENTRY *EGLImageTargetTexture2DProc)(GrGLenum, GrGLeglImage);
287     EGLImageTargetTexture2DProc glEGLImageTargetTexture2D =
288         (EGLImageTargetTexture2DProc)eglGetProcAddress("glEGLImageTargetTexture2DOES");
289     if (!glEGLImageTargetTexture2D) {
290         return 0;
291     }
292     GrGLuint texID;
293     GR_GL_CALL(this->gl(), GenTextures(1, &texID));
294     if (!texID) {
295         return 0;
296     }
297     GR_GL_CALL(this->gl(), BindTexture(GR_GL_TEXTURE_EXTERNAL, texID));
298     if (GR_GL_GET_ERROR(this->gl()) != GR_GL_NO_ERROR) {
299         GR_GL_CALL(this->gl(), DeleteTextures(1, &texID));
300         return 0;
301     }
302     glEGLImageTargetTexture2D(GR_GL_TEXTURE_EXTERNAL, image);
303     if (GR_GL_GET_ERROR(this->gl()) != GR_GL_NO_ERROR) {
304         GR_GL_CALL(this->gl(), DeleteTextures(1, &texID));
305         return 0;
306     }
307     return texID;
308 }
309 
makeNew() const310 std::unique_ptr<sk_gpu_test::GLTestContext> ANGLEGLContext::makeNew() const {
311     // For EGLImage sharing between contexts to work in ANGLE the two contexts
312     // need to share the same display
313     std::unique_ptr<sk_gpu_test::GLTestContext> ctx =
314         sk_gpu_test::MakeANGLETestContext(fType, fVersion, nullptr, fDisplay);
315     if (ctx) {
316         ctx->makeCurrent();
317     }
318     return ctx;
319 }
320 
destroyGLContext()321 void ANGLEGLContext::destroyGLContext() {
322     if (EGL_NO_DISPLAY != fDisplay) {
323         eglMakeCurrent(fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
324 
325         if (EGL_NO_CONTEXT != fContext) {
326             eglDestroyContext(fDisplay, fContext);
327             fContext = EGL_NO_CONTEXT;
328         }
329 
330         if (EGL_NO_SURFACE != fSurface) {
331             eglDestroySurface(fDisplay, fSurface);
332             fSurface = EGL_NO_SURFACE;
333         }
334 
335         eglTerminate(fDisplay);
336         fDisplay = EGL_NO_DISPLAY;
337     }
338 
339 #ifdef SK_BUILD_FOR_WIN
340     if (fWindow) {
341         if (fDeviceContext) {
342             ReleaseDC(fWindow, fDeviceContext);
343             fDeviceContext = 0;
344         }
345 
346         DestroyWindow(fWindow);
347         fWindow = 0;
348     }
349 #endif
350 }
351 
onPlatformMakeCurrent() const352 void ANGLEGLContext::onPlatformMakeCurrent() const {
353     if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
354         SkDebugf("Could not set the context 0x%x.\n", eglGetError());
355     }
356 }
357 
onPlatformSwapBuffers() const358 void ANGLEGLContext::onPlatformSwapBuffers() const {
359     if (!eglSwapBuffers(fDisplay, fSurface)) {
360         SkDebugf("Could not complete eglSwapBuffers.\n");
361     }
362 }
363 
onPlatformGetProcAddress(const char * name) const364 GrGLFuncPtr ANGLEGLContext::onPlatformGetProcAddress(const char* name) const {
365     return eglGetProcAddress(name);
366 }
367 }  // anonymous namespace
368 
369 namespace sk_gpu_test {
CreateANGLEGLInterface()370 const GrGLInterface* CreateANGLEGLInterface() {
371     static Libs gLibs = { nullptr, nullptr };
372 
373     if (nullptr == gLibs.fGLLib) {
374         // We load the ANGLE library and never let it go
375 #if defined _WIN32
376         gLibs.fGLLib = DynamicLoadLibrary("libGLESv2.dll");
377         gLibs.fEGLLib = DynamicLoadLibrary("libEGL.dll");
378 #elif defined SK_BUILD_FOR_MAC
379         gLibs.fGLLib = DynamicLoadLibrary("libGLESv2.dylib");
380         gLibs.fEGLLib = DynamicLoadLibrary("libEGL.dylib");
381 #else
382         gLibs.fGLLib = DynamicLoadLibrary("libGLESv2.so");
383         gLibs.fEGLLib = DynamicLoadLibrary("libEGL.so");
384 #endif
385     }
386 
387     if (nullptr == gLibs.fGLLib || nullptr == gLibs.fEGLLib) {
388         // We can't setup the interface correctly w/o the so
389         return nullptr;
390     }
391 
392     return GrGLAssembleGLESInterface(&gLibs, angle_get_gl_proc);
393 }
394 
MakeANGLETestContext(ANGLEBackend type,ANGLEContextVersion version,GLTestContext * shareContext,void * display)395 std::unique_ptr<GLTestContext> MakeANGLETestContext(ANGLEBackend type, ANGLEContextVersion version,
396                                                     GLTestContext* shareContext, void* display){
397     ANGLEGLContext* angleShareContext = reinterpret_cast<ANGLEGLContext*>(shareContext);
398     std::unique_ptr<GLTestContext> ctx(new ANGLEGLContext(type, version,
399                                                           angleShareContext, display));
400     if (!ctx->isValid()) {
401         return nullptr;
402     }
403     return ctx;
404 }
405 }  // namespace sk_gpu_test
406