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
29using sk_gpu_test::ANGLEBackend;
30using sk_gpu_test::ANGLEContextVersion;
31
32namespace {
33struct Libs {
34    void* fGLLib;
35    void* fEGLLib;
36};
37
38static 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
51void* 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
77class ANGLEGLContext : public sk_gpu_test::GLTestContext {
78public:
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
87private:
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
101ANGLEGLContext::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
167ANGLEGLContext::~ANGLEGLContext() {
168    this->teardown();
169    this->destroyGLContext();
170}
171
172GrEGLImage 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
188void ANGLEGLContext::destroyEGLImage(GrEGLImage image) const {
189    GR_GL_CALL(this->gl(), EGLDestroyImage(fDisplay, image));
190}
191
192GrGLuint 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
221std::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
230void 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
249void ANGLEGLContext::onPlatformMakeCurrent() const {
250    if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
251        SkDebugf("Could not set the context.\n");
252    }
253}
254
255void ANGLEGLContext::onPlatformSwapBuffers() const {
256    if (!eglSwapBuffers(fDisplay, fSurface)) {
257        SkDebugf("Could not complete eglSwapBuffers.\n");
258    }
259}
260
261GrGLFuncPtr ANGLEGLContext::onPlatformGetProcAddress(const char* name) const {
262    return eglGetProcAddress(name);
263}
264}  // anonymous namespace
265
266namespace sk_gpu_test {
267const 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
292std::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