diff options
Diffstat (limited to 'services/surfaceflinger/RenderEngine')
-rw-r--r-- | services/surfaceflinger/RenderEngine/RenderEngine.cpp | 217 | ||||
-rw-r--r-- | services/surfaceflinger/RenderEngine/RenderEngine.h | 10 |
2 files changed, 216 insertions, 11 deletions
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp index ba82cad..2871ce9 100644 --- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp @@ -25,19 +25,51 @@ #include "GLExtensions.h" #include "Mesh.h" +EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); + // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- -RenderEngine* RenderEngine::create(EGLDisplay display, EGLConfig config) { - EGLint renderableType = 0; - EGLint contextClientVersion = 0; +static bool findExtension(const char* exts, const char* name) { + if (!exts) + return false; + size_t len = strlen(name); - // query the renderable type, setting the EGL_CONTEXT_CLIENT_VERSION accordingly - if (!eglGetConfigAttrib(display, config, EGL_RENDERABLE_TYPE, &renderableType)) { - LOG_ALWAYS_FATAL("can't query EGLConfig RENDERABLE_TYPE"); + const char* pos = exts; + while ((pos = strstr(pos, name)) != NULL) { + if (pos[len] == '\0' || pos[len] == ' ') + return true; + pos += len; } + return false; +} + +RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat) { + // EGL_ANDROIDX_no_config_context is an experimental extension with no + // written specification. It will be replaced by something more formal. + // SurfaceFlinger is using it to allow a single EGLContext to render to + // both a 16-bit primary display framebuffer and a 32-bit virtual display + // framebuffer. + // + // The code assumes that ES2 or later is available if this extension is + // supported. + EGLConfig config = EGL_NO_CONFIG; + if (!findExtension( + eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS), + "EGL_ANDROIDX_no_config_context")) { + config = chooseEglConfig(display, hwcFormat); + } + + EGLint renderableType = 0; + if (config == EGL_NO_CONFIG) { + renderableType = EGL_OPENGL_ES2_BIT; + } else if (!eglGetConfigAttrib(display, config, + EGL_RENDERABLE_TYPE, &renderableType)) { + LOG_ALWAYS_FATAL("can't query EGLConfig RENDERABLE_TYPE"); + } + EGLint contextClientVersion = 0; if (renderableType & EGL_OPENGL_ES2_BIT) { contextClientVersion = 2; } else if (renderableType & EGL_OPENGL_ES_BIT) { @@ -66,8 +98,12 @@ RenderEngine* RenderEngine::create(EGLDisplay display, EGLConfig config) { // now figure out what version of GL did we actually get // NOTE: a dummy surface is not needed if KHR_create_context is supported + EGLConfig dummyConfig = config; + if (dummyConfig == EGL_NO_CONFIG) { + dummyConfig = chooseEglConfig(display, hwcFormat); + } EGLint attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE }; - EGLSurface dummy = eglCreatePbufferSurface(display, config, attribs); + EGLSurface dummy = eglCreatePbufferSurface(display, dummyConfig, attribs); LOG_ALWAYS_FATAL_IF(dummy==EGL_NO_SURFACE, "can't create dummy pbuffer"); EGLBoolean success = eglMakeCurrent(display, dummy, dummy, ctxt); LOG_ALWAYS_FATAL_IF(!success, "can't make dummy pbuffer current"); @@ -96,7 +132,7 @@ RenderEngine* RenderEngine::create(EGLDisplay display, EGLConfig config) { engine = new GLES20RenderEngine(); break; } - engine->setEGLContext(ctxt); + engine->setEGLHandles(config, ctxt); ALOGI("OpenGL ES informations:"); ALOGI("vendor : %s", extensions.getVendor()); @@ -118,10 +154,15 @@ RenderEngine::RenderEngine() : mEGLContext(EGL_NO_CONTEXT) { RenderEngine::~RenderEngine() { } -void RenderEngine::setEGLContext(EGLContext ctxt) { +void RenderEngine::setEGLHandles(EGLConfig config, EGLContext ctxt) { + mEGLConfig = config; mEGLContext = ctxt; } +EGLContext RenderEngine::getEGLConfig() const { + return mEGLConfig; +} + EGLContext RenderEngine::getEGLContext() const { return mEGLContext; } @@ -235,5 +276,163 @@ status_t RenderEngine::BindImageAsFramebuffer::getStatus() const { } // --------------------------------------------------------------------------- + +static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs, + EGLint attribute, EGLint wanted, EGLConfig* outConfig) { + EGLConfig config = NULL; + EGLint numConfigs = -1, n = 0; + eglGetConfigs(dpy, NULL, 0, &numConfigs); + EGLConfig* const configs = new EGLConfig[numConfigs]; + eglChooseConfig(dpy, attrs, configs, numConfigs, &n); + + if (n) { + if (attribute != EGL_NONE) { + for (int i=0 ; i<n ; i++) { + EGLint value = 0; + eglGetConfigAttrib(dpy, configs[i], attribute, &value); + if (wanted == value) { + *outConfig = configs[i]; + delete [] configs; + return NO_ERROR; + } + } + } else { + // just pick the first one + *outConfig = configs[0]; + delete [] configs; + return NO_ERROR; + } + } + delete [] configs; + return NAME_NOT_FOUND; +} + +class EGLAttributeVector { + struct Attribute; + class Adder; + friend class Adder; + KeyedVector<Attribute, EGLint> mList; + struct Attribute { + Attribute() {}; + Attribute(EGLint v) : v(v) { } + EGLint v; + bool operator < (const Attribute& other) const { + // this places EGL_NONE at the end + EGLint lhs(v); + EGLint rhs(other.v); + if (lhs == EGL_NONE) lhs = 0x7FFFFFFF; + if (rhs == EGL_NONE) rhs = 0x7FFFFFFF; + return lhs < rhs; + } + }; + class Adder { + friend class EGLAttributeVector; + EGLAttributeVector& v; + EGLint attribute; + Adder(EGLAttributeVector& v, EGLint attribute) + : v(v), attribute(attribute) { + } + public: + void operator = (EGLint value) { + if (attribute != EGL_NONE) { + v.mList.add(attribute, value); + } + } + operator EGLint () const { return v.mList[attribute]; } + }; +public: + EGLAttributeVector() { + mList.add(EGL_NONE, EGL_NONE); + } + void remove(EGLint attribute) { + if (attribute != EGL_NONE) { + mList.removeItem(attribute); + } + } + Adder operator [] (EGLint attribute) { + return Adder(*this, attribute); + } + EGLint operator [] (EGLint attribute) const { + return mList[attribute]; + } + // cast-operator to (EGLint const*) + operator EGLint const* () const { return &mList.keyAt(0).v; } +}; + + +static status_t selectEGLConfig(EGLDisplay display, EGLint format, + EGLint renderableType, EGLConfig* config) { + // select our EGLConfig. It must support EGL_RECORDABLE_ANDROID if + // it is to be used with WIFI displays + status_t err; + EGLint wantedAttribute; + EGLint wantedAttributeValue; + + EGLAttributeVector attribs; + if (renderableType) { + attribs[EGL_RENDERABLE_TYPE] = renderableType; + attribs[EGL_RECORDABLE_ANDROID] = EGL_TRUE; + attribs[EGL_SURFACE_TYPE] = EGL_WINDOW_BIT|EGL_PBUFFER_BIT; + attribs[EGL_FRAMEBUFFER_TARGET_ANDROID] = EGL_TRUE; + attribs[EGL_RED_SIZE] = 8; + attribs[EGL_GREEN_SIZE] = 8; + attribs[EGL_BLUE_SIZE] = 8; + wantedAttribute = EGL_NONE; + wantedAttributeValue = EGL_NONE; + } else { + // if no renderable type specified, fallback to a simplified query + wantedAttribute = EGL_NATIVE_VISUAL_ID; + wantedAttributeValue = format; + } + + err = selectConfigForAttribute(display, attribs, + wantedAttribute, wantedAttributeValue, config); + if (err == NO_ERROR) { + EGLint caveat; + if (eglGetConfigAttrib(display, *config, EGL_CONFIG_CAVEAT, &caveat)) + ALOGW_IF(caveat == EGL_SLOW_CONFIG, "EGL_SLOW_CONFIG selected!"); + } + + return err; +} + +EGLConfig RenderEngine::chooseEglConfig(EGLDisplay display, int format) { + status_t err; + EGLConfig config; + + // First try to get an ES2 config + err = selectEGLConfig(display, format, EGL_OPENGL_ES2_BIT, &config); + if (err != NO_ERROR) { + // If ES2 fails, try ES1 + err = selectEGLConfig(display, format, EGL_OPENGL_ES_BIT, &config); + if (err != NO_ERROR) { + // still didn't work, probably because we're on the emulator... + // try a simplified query + ALOGW("no suitable EGLConfig found, trying a simpler query"); + err = selectEGLConfig(display, format, 0, &config); + if (err != NO_ERROR) { + // this EGL is too lame for android + LOG_ALWAYS_FATAL("no suitable EGLConfig found, giving up"); + } + } + } + + // print some debugging info + EGLint r,g,b,a; + eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r); + eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g); + eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b); + eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a); + ALOGI("EGL information:"); + ALOGI("vendor : %s", eglQueryString(display, EGL_VENDOR)); + ALOGI("version : %s", eglQueryString(display, EGL_VERSION)); + ALOGI("extensions: %s", eglQueryString(display, EGL_EXTENSIONS)); + ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported"); + ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config); + + return config; +} + +// --------------------------------------------------------------------------- }; // namespace android // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h index 3c7f9ab..577dc0a 100644 --- a/services/surfaceflinger/RenderEngine/RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/RenderEngine.h @@ -25,6 +25,8 @@ #include <EGL/eglext.h> #include <ui/mat4.h> +#define EGL_NO_CONFIG ((EGLConfig)0) + // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- @@ -44,8 +46,9 @@ class RenderEngine { }; static GlesVersion parseGlesVersion(const char* str); + EGLConfig mEGLConfig; EGLContext mEGLContext; - void setEGLContext(EGLContext ctxt); + void setEGLHandles(EGLConfig config, EGLContext ctxt); virtual void bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName, uint32_t* fbName, uint32_t* status) = 0; virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName) = 0; @@ -55,7 +58,9 @@ protected: virtual ~RenderEngine() = 0; public: - static RenderEngine* create(EGLDisplay display, EGLConfig config); + static RenderEngine* create(EGLDisplay display, int hwcFormat); + + static EGLConfig chooseEglConfig(EGLDisplay display, int format); // dump the extension strings. always call the base class. virtual void dump(String8& result); @@ -107,6 +112,7 @@ public: virtual size_t getMaxTextureSize() const = 0; virtual size_t getMaxViewportDims() const = 0; + EGLConfig getEGLConfig() const; EGLContext getEGLContext() const; }; |