blob: 4e5138641a37a5dbb000693618046b702637eb20 [file] [log] [blame] [edit]
/*
* 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