| /* | |
| * Copyright 2023 Google LLC | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #include <EGL/egl.h> | |
| #include <GLES/gl.h> | |
| #include "include/gpu/ganesh/gl/GrGLInterface.h" | |
| #include "tools/window/DisplayParams.h" | |
| #include "tools/window/GLWindowContext.h" | |
| #include "tools/window/android/WindowContextFactory_android.h" | |
| #define EGL_PROTECTED_CONTENT_EXT 0x32C0 | |
| using skwindow::DisplayParams; | |
| namespace { | |
| class GLWindowContext_android : public skwindow::internal::GLWindowContext { | |
| public: | |
| GLWindowContext_android(ANativeWindow*, std::unique_ptr<const DisplayParams>); | |
| ~GLWindowContext_android() override; | |
| sk_sp<const GrGLInterface> onInitializeContext() override; | |
| void onDestroyContext() override; | |
| private: | |
| void onSwapBuffers() override; | |
| EGLDisplay fDisplay; | |
| EGLContext fEGLContext; | |
| EGLSurface fSurfaceAndroid; | |
| // For setDisplayParams and resize which call onInitializeContext with null platformData | |
| ANativeWindow* fNativeWindow = nullptr; | |
| }; | |
| GLWindowContext_android::GLWindowContext_android(ANativeWindow* window, | |
| std::unique_ptr<const DisplayParams> params) | |
| : GLWindowContext(std::move(params)) | |
| , fDisplay(EGL_NO_DISPLAY) | |
| , fEGLContext(EGL_NO_CONTEXT) | |
| , fSurfaceAndroid(EGL_NO_SURFACE) | |
| , fNativeWindow(window) { | |
| // any config code here (particularly for msaa)? | |
| this->initializeContext(); | |
| } | |
| GLWindowContext_android::~GLWindowContext_android() { | |
| this->destroyContext(); | |
| } | |
| sk_sp<const GrGLInterface> GLWindowContext_android::onInitializeContext() { | |
| fWidth = ANativeWindow_getWidth(fNativeWindow); | |
| fHeight = ANativeWindow_getHeight(fNativeWindow); | |
| fDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); | |
| EGLint majorVersion; | |
| EGLint minorVersion; | |
| eglInitialize(fDisplay, &majorVersion, &minorVersion); | |
| const char* extensions = eglQueryString(fDisplay, EGL_EXTENSIONS); | |
| if (fDisplayParams->createProtectedNativeBackend() && | |
| !strstr(extensions, "EGL_EXT_protected_content")) { | |
| SkDebugf("Protected Context requested but no protected support\n"); | |
| fDisplayParams = skwindow::DisplayParamsBuilder(fDisplayParams.get()) | |
| .createProtectedNativeBackend(false) | |
| .detach(); | |
| } | |
| SkAssertResult(eglBindAPI(EGL_OPENGL_ES_API)); | |
| EGLint numConfigs = 0; | |
| EGLint eglSampleCnt = | |
| fDisplayParams->msaaSampleCount() > 1 ? fDisplayParams->msaaSampleCount() > 1 : 0; | |
| const EGLint configAttribs[] = { | |
| EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, | |
| EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, | |
| EGL_RED_SIZE, 8, | |
| EGL_GREEN_SIZE, 8, | |
| EGL_BLUE_SIZE, 8, | |
| EGL_ALPHA_SIZE, 8, | |
| EGL_STENCIL_SIZE, 8, | |
| EGL_SAMPLE_BUFFERS, eglSampleCnt ? 1 : 0, | |
| EGL_SAMPLES, eglSampleCnt, | |
| EGL_NONE | |
| }; | |
| EGLConfig surfaceConfig; | |
| SkAssertResult(eglChooseConfig(fDisplay, configAttribs, &surfaceConfig, 1, &numConfigs)); | |
| SkASSERT(numConfigs > 0); | |
| std::vector<EGLint> kEGLContextAttribsForOpenGLES = { | |
| EGL_CONTEXT_CLIENT_VERSION, 2, | |
| }; | |
| if (fDisplayParams->createProtectedNativeBackend()) { | |
| kEGLContextAttribsForOpenGLES.push_back(EGL_PROTECTED_CONTENT_EXT); | |
| kEGLContextAttribsForOpenGLES.push_back(EGL_TRUE); | |
| } | |
| kEGLContextAttribsForOpenGLES.push_back(EGL_NONE); | |
| fEGLContext = eglCreateContext( | |
| fDisplay, surfaceConfig, nullptr, kEGLContextAttribsForOpenGLES.data()); | |
| SkASSERT(EGL_NO_CONTEXT != fEGLContext); | |
| // SkDebugf("EGL: %d.%d", majorVersion, minorVersion); | |
| // SkDebugf("Vendor: %s", eglQueryString(fDisplay, EGL_VENDOR)); | |
| // SkDebugf("Extensions: %s", eglQueryString(fDisplay, EGL_EXTENSIONS)); | |
| const EGLint surfaceAttribs[] = { | |
| fDisplayParams->createProtectedNativeBackend() ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE, | |
| fDisplayParams->createProtectedNativeBackend() ? EGL_TRUE : EGL_NONE, | |
| EGL_NONE}; | |
| fSurfaceAndroid = eglCreateWindowSurface(fDisplay, surfaceConfig, fNativeWindow, | |
| surfaceAttribs); | |
| SkASSERT(EGL_NO_SURFACE != fSurfaceAndroid); | |
| SkAssertResult(eglMakeCurrent(fDisplay, fSurfaceAndroid, fSurfaceAndroid, fEGLContext)); | |
| // GLWindowContext::initializeContext will call GrGLMakeNativeInterface so we | |
| // won't call it here. | |
| glClearStencil(0); | |
| glClearColor(0, 0, 0, 0); | |
| glStencilMask(0xffffffff); | |
| glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); | |
| eglGetConfigAttrib(fDisplay, surfaceConfig, EGL_STENCIL_SIZE, &fStencilBits); | |
| eglGetConfigAttrib(fDisplay, surfaceConfig, EGL_SAMPLES, &fSampleCount); | |
| fSampleCount = std::max(fSampleCount, 1); | |
| eglSwapInterval(fDisplay, fDisplayParams->disableVsync() ? 0 : 1); | |
| return GrGLMakeNativeInterface(); | |
| } | |
| void GLWindowContext_android::onDestroyContext() { | |
| if (!fDisplay || !fEGLContext || !fSurfaceAndroid) { | |
| return; | |
| } | |
| eglMakeCurrent(fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); | |
| SkAssertResult(eglDestroySurface(fDisplay, fSurfaceAndroid)); | |
| SkAssertResult(eglDestroyContext(fDisplay, fEGLContext)); | |
| fEGLContext = EGL_NO_CONTEXT; | |
| fSurfaceAndroid = EGL_NO_SURFACE; | |
| } | |
| void GLWindowContext_android::onSwapBuffers() { | |
| if (fDisplay && fEGLContext && fSurfaceAndroid) { | |
| eglSwapBuffers(fDisplay, fSurfaceAndroid); | |
| } | |
| } | |
| } // anonymous namespace | |
| namespace skwindow { | |
| std::unique_ptr<WindowContext> MakeGLForAndroid(ANativeWindow* window, | |
| std::unique_ptr<const DisplayParams> params) { | |
| std::unique_ptr<WindowContext> ctx(new GLWindowContext_android(window, std::move(params))); | |
| if (!ctx->isValid()) { | |
| return nullptr; | |
| } | |
| return ctx; | |
| } | |
| } // namespace skwindow |