diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9a8fe0a0dd637c6a11b4f8c5f9097dfcb72b9b56..5675ccbe5b9e4dcff81d80d1f6aead5db1201d04 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 diff --git a/src/anbox/graphics/emugl/Renderer.cpp b/src/anbox/graphics/emugl/Renderer.cpp index cdea661b3a403709d7ea77e5d62605ba1493c5dd..664c2f785d27e96767be3c6c61f97b2840125d74 100644 --- a/src/anbox/graphics/emugl/Renderer.cpp +++ b/src/anbox/graphics/emugl/Renderer.cpp @@ -23,6 +23,8 @@ #include "OpenGLESDispatch/EGLDispatch.h" +#include "anbox/graphics/gl_extensions.h" + #include "anbox/logger.h" #include @@ -78,7 +80,6 @@ class ColorBufferHelper : public ColorBuffer::Helper { private: Renderer *mFb; }; - } // namespace HandleType Renderer::s_nextHandle = 0; @@ -105,11 +106,9 @@ static char *getGLES1ExtensionString(EGLDisplay p_dpy) { return NULL; } - static const GLint gles1ContextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 1, - EGL_NONE}; + static const GLint gles1ContextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 1, EGL_NONE}; - EGLContext ctx = s_egl.eglCreateContext(p_dpy, config, EGL_NO_CONTEXT, - gles1ContextAttribs); + 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); @@ -156,6 +155,12 @@ bool Renderer::initialize(EGLNativeDisplayType nativeDisplay) { return false; } + anbox::graphics::GLExtensions egl_extensions{s_egl.eglQueryString(m_eglDisplay, EGL_EXTENSIONS)}; + + 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); // If GLES2 plugin was loaded - try to make GLES2 context and @@ -201,24 +206,27 @@ 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()); + free(gles1Extensions); + return false; + } + } else { + DEBUG("Using a surfaceless EGL context"); + m_pbufSurface = EGL_NO_SURFACE; } // Make the context current diff --git a/src/anbox/graphics/gl_extensions.h b/src/anbox/graphics/gl_extensions.h new file mode 100644 index 0000000000000000000000000000000000000000..7b5738f294a5fb2851694fa58e78447110cbe8d0 --- /dev/null +++ b/src/anbox/graphics/gl_extensions.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2017 Simon Fels + * + * 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 . + * + */ + +#ifndef ANBOX_GRAPHICS_GL_EXTENSIONS_H_ +#define ANBOX_GRAPHICS_GL_EXTENSIONS_H_ + +#include +#include + +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