Merge pull request #68 from morphis/f/surfaceless-context

Use surfaceless main context when possible
This commit is contained in:
Simon Fels 2017-04-09 18:24:15 +02:00 committed by GitHub
commit 73d3ce65e8
3 changed files with 79 additions and 90 deletions

View file

@ -125,6 +125,7 @@ set(SOURCES
anbox/graphics/program_family.cpp
anbox/graphics/primitives.h
anbox/graphics/renderer.h
anbox/graphics/gl_extensions.h
anbox/graphics/emugl/ColorBuffer.cpp
anbox/graphics/emugl/DisplayManager.cpp

View file

@ -23,6 +23,8 @@
#include "OpenGLESDispatch/EGLDispatch.h"
#include "anbox/graphics/gl_extensions.h"
#include "anbox/logger.h"
#include <stdio.h>
@ -78,62 +80,10 @@ class ColorBufferHelper : public ColorBuffer::Helper {
private:
Renderer *mFb;
};
} // namespace
HandleType Renderer::s_nextHandle = 0;
static char *getGLES1ExtensionString(EGLDisplay p_dpy) {
EGLConfig config;
EGLSurface surface;
static const GLint configAttribs[] = {EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
EGL_NONE};
int n;
if (!s_egl.eglChooseConfig(p_dpy, configAttribs, &config, 1, &n) || n == 0) {
ERROR("%s: Could not find GLES 1.x config!", __FUNCTION__);
return NULL;
}
static const EGLint pbufAttribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
surface = s_egl.eglCreatePbufferSurface(p_dpy, config, pbufAttribs);
if (surface == EGL_NO_SURFACE) {
ERROR("%s: Could not create GLES 1.x Pbuffer!", __FUNCTION__);
return NULL;
}
static const GLint gles1ContextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 1,
EGL_NONE};
EGLContext ctx = s_egl.eglCreateContext(p_dpy, config, EGL_NO_CONTEXT,
gles1ContextAttribs);
if (ctx == EGL_NO_CONTEXT) {
ERROR("%s: Could not create GLES 1.x Context!", __FUNCTION__);
s_egl.eglDestroySurface(p_dpy, surface);
return NULL;
}
if (!s_egl.eglMakeCurrent(p_dpy, surface, surface, ctx)) {
ERROR("%s: Could not make GLES 1.x context current!", __FUNCTION__);
s_egl.eglDestroySurface(p_dpy, surface);
s_egl.eglDestroyContext(p_dpy, ctx);
return NULL;
}
// the string pointer may become invalid when the context is destroyed
const char *s = reinterpret_cast<const char *>(s_gles1.glGetString(GL_EXTENSIONS));
char *extString = strdup(s ? s : "");
s_egl.eglMakeCurrent(p_dpy, NULL, NULL, NULL);
s_egl.eglDestroyContext(p_dpy, ctx);
s_egl.eglDestroySurface(p_dpy, surface);
return extString;
}
void Renderer::finalize() {
m_colorbuffers.clear();
m_windows.clear();
@ -156,16 +106,13 @@ bool Renderer::initialize(EGLNativeDisplayType nativeDisplay) {
return false;
}
s_egl.eglBindAPI(EGL_OPENGL_ES_API);
anbox::graphics::GLExtensions egl_extensions{s_egl.eglQueryString(m_eglDisplay, EGL_EXTENSIONS)};
// If GLES2 plugin was loaded - try to make GLES2 context and
// get GLES2 extension string
char *gles1Extensions = NULL;
gles1Extensions = getGLES1ExtensionString(m_eglDisplay);
if (!gles1Extensions) {
ERROR("Failed to obtain GLES 2.x extensions string!");
return false;
}
const auto surfaceless_supported = egl_extensions.support("EGL_KHR_surfaceless_context");
if (!surfaceless_supported)
DEBUG("EGL doesn't support surfaceless context");
s_egl.eglBindAPI(EGL_OPENGL_ES_API);
// Create EGL context for framebuffer post rendering.
GLint surfaceType = EGL_WINDOW_BIT | EGL_PBUFFER_BIT;
@ -180,7 +127,6 @@ bool Renderer::initialize(EGLNativeDisplayType nativeDisplay) {
if (!s_egl.eglChooseConfig(m_eglDisplay, configAttribs, &m_eglConfig,
1, &n)) {
ERROR("Failed to select EGL configuration");
free(gles1Extensions);
return false;
}
@ -191,7 +137,6 @@ bool Renderer::initialize(EGLNativeDisplayType nativeDisplay) {
EGL_NO_CONTEXT, glContextAttribs);
if (m_eglContext == EGL_NO_CONTEXT) {
ERROR("Failed to create context: error=0x%x", s_egl.eglGetError());
free(gles1Extensions);
return false;
}
@ -201,47 +146,38 @@ bool Renderer::initialize(EGLNativeDisplayType nativeDisplay) {
// The main purpose of it is to solve a "blanking" behaviour we see on
// on Mac platform when switching binded drawable for a context however
// it is more efficient on other platforms as well.
m_pbufContext = s_egl.eglCreateContext(
m_eglDisplay, m_eglConfig, m_eglContext, glContextAttribs);
m_pbufContext = s_egl.eglCreateContext(m_eglDisplay, m_eglConfig, m_eglContext, glContextAttribs);
if (m_pbufContext == EGL_NO_CONTEXT) {
ERROR("Failed to create pbuffer context: error=0x%x", s_egl.eglGetError());
free(gles1Extensions);
return false;
}
// Create a 1x1 pbuffer surface which will be used for binding
// the FB context. The FB output will go to a subwindow, if one exist.
static const EGLint pbufAttribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
if (!surfaceless_supported) {
// Create a 1x1 pbuffer surface which will be used for binding
// the FB context. The FB output will go to a subwindow, if one exist.
static const EGLint pbufAttribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
m_pbufSurface = s_egl.eglCreatePbufferSurface(
m_eglDisplay, m_eglConfig, pbufAttribs);
if (m_pbufSurface == EGL_NO_SURFACE) {
ERROR("Failed to create pbuffer surface: error=0x%x", s_egl.eglGetError());
free(gles1Extensions);
return false;
m_pbufSurface = s_egl.eglCreatePbufferSurface(m_eglDisplay, m_eglConfig, pbufAttribs);
if (m_pbufSurface == EGL_NO_SURFACE) {
ERROR("Failed to create pbuffer surface: error=0x%x", s_egl.eglGetError());
return false;
}
} else {
DEBUG("Using a surfaceless EGL context");
m_pbufSurface = EGL_NO_SURFACE;
}
// Make the context current
ScopedBind bind(this);
if (!bind.isValid()) {
ERROR("Failed to make current");
free(gles1Extensions);
return false;
}
// Initilize framebuffer capabilities
auto has_gl_oes_image = strstr(gles1Extensions, "GL_OES_EGL_image") != NULL;
free(gles1Extensions);
gles1Extensions = NULL;
const char *eglExtensions =
s_egl.eglQueryString(m_eglDisplay, EGL_EXTENSIONS);
if (eglExtensions && has_gl_oes_image) {
m_caps.has_eglimage_texture_2d =
strstr(eglExtensions, "EGL_KHR_gl_texture_2D_image") != NULL;
m_caps.has_eglimage_renderbuffer =
strstr(eglExtensions, "EGL_KHR_gl_renderbuffer_image") != NULL;
anbox::graphics::GLExtensions gl_extensions{reinterpret_cast<const char *>(s_gles2.glGetString(GL_EXTENSIONS))};
if (gl_extensions.support("GL_OES_EGL_image")) {
m_caps.has_eglimage_texture_2d = egl_extensions.support("EGL_KHR_gl_texture_2D_image");
m_caps.has_eglimage_renderbuffer = egl_extensions.support("EGL_KHR_gl_renderbuffer_image");
} else {
m_caps.has_eglimage_texture_2d = false;
m_caps.has_eglimage_renderbuffer = false;
@ -250,7 +186,7 @@ bool Renderer::initialize(EGLNativeDisplayType nativeDisplay) {
// Fail initialization if not all of the following extensions
// exist:
// EGL_KHR_gl_texture_2d_image
// GL_OES_EGL_IMAGE (by both GLES implementations [1 and 2])
// GL_OES_EGL_IMAGE
if (!m_caps.has_eglimage_texture_2d) {
ERROR("Failed: Missing egl_image related extension(s)");
bind.release();

View file

@ -0,0 +1,52 @@
/*
* Copyright (C) 2017 Simon Fels <morphis@gravedo.de>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ANBOX_GRAPHICS_GL_EXTENSIONS_H_
#define ANBOX_GRAPHICS_GL_EXTENSIONS_H_
#include <stdexcept>
#include <string.h>
namespace anbox {
namespace graphics {
class GLExtensions {
public:
GLExtensions(char const* extensions) : extensions{extensions} {
if (!extensions)
throw std::runtime_error("Couldn't get list of GL extensions");
}
bool support(char const* ext) const {
char const* ext_ptr = extensions;
size_t const len = strlen(ext);
while ((ext_ptr = strstr(ext_ptr, ext)) != nullptr) {
if (ext_ptr[len] == ' ' || ext_ptr[len] == '\0')
break;
ext_ptr += len;
}
return ext_ptr != nullptr;
}
char const* raw() { return extensions; }
private:
char const* extensions;
};
} // namespace graphics
} // namespace anbox
#endif