factor EGL/GL and surface creation out of DisplayHardware
Change-Id: Icd85a6a4caad06f056578008af3e21666fa8b1f4
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 46a711d..29ec1a7 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -59,6 +59,7 @@
#include "LayerScreenshot.h"
#include "SurfaceFlinger.h"
+#include "DisplayHardware/FramebufferSurface.h"
#include "DisplayHardware/HWComposer.h"
#include <private/android_filesystem_config.h>
@@ -141,6 +142,9 @@
SurfaceFlinger::~SurfaceFlinger()
{
glDeleteTextures(1, &mWormholeTexName);
+ EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ eglTerminate(display);
}
void SurfaceFlinger::binderDied(const wp<IBinder>& who)
@@ -197,59 +201,95 @@
property_set("service.bootanim.exit", "1");
}
-static inline uint16_t pack565(int r, int g, int b) {
- return (r<<11)|(g<<5)|b;
+status_t SurfaceFlinger::selectConfigForPixelFormat(
+ EGLDisplay dpy,
+ EGLint const* attrs,
+ PixelFormat format,
+ 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);
+ for (int i=0 ; i<n ; i++) {
+ EGLint nativeVisualId = 0;
+ eglGetConfigAttrib(dpy, configs[i], EGL_NATIVE_VISUAL_ID, &nativeVisualId);
+ if (nativeVisualId>0 && format == nativeVisualId) {
+ *outConfig = configs[i];
+ delete [] configs;
+ return NO_ERROR;
+ }
+ }
+ delete [] configs;
+ return NAME_NOT_FOUND;
}
-status_t SurfaceFlinger::readyToRun()
-{
- ALOGI( "SurfaceFlinger's main thread ready to run. "
- "Initializing graphics H/W...");
+EGLConfig SurfaceFlinger::selectEGLConfig(EGLDisplay display, EGLint nativeVisualId) {
+ // select our EGLConfig. It must support EGL_RECORDABLE_ANDROID if
+ // it is to be used with WIFI displays
+ EGLConfig config;
+ EGLint dummy;
+ status_t err;
+ EGLint attribs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RECORDABLE_ANDROID, EGL_TRUE,
+ EGL_NONE
+ };
+ err = selectConfigForPixelFormat(display, attribs, nativeVisualId, &config);
+ if (err) {
+ // maybe we failed because of EGL_RECORDABLE_ANDROID
+ ALOGW("couldn't find an EGLConfig with EGL_RECORDABLE_ANDROID");
+ attribs[2] = EGL_NONE;
+ err = selectConfigForPixelFormat(display, attribs, nativeVisualId, &config);
+ }
+ ALOGE_IF(err, "couldn't find an EGLConfig matching the screen format");
+ if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy) == EGL_TRUE) {
+ ALOGW_IF(dummy == EGL_SLOW_CONFIG, "EGL_SLOW_CONFIG selected!");
+ }
+ return config;
+}
- // we only support one display currently
- int dpy = 0;
+EGLContext SurfaceFlinger::createGLContext(EGLDisplay display, EGLConfig config) {
+ // Also create our EGLContext
+ EGLint contextAttributes[] = {
+#ifdef EGL_IMG_context_priority
+#ifdef HAS_CONTEXT_PRIORITY
+#warning "using EGL_IMG_context_priority"
+ EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG,
+#endif
+#endif
+ EGL_NONE, EGL_NONE
+ };
+ EGLContext ctxt = eglCreateContext(display, config, NULL, contextAttributes);
+ ALOGE_IF(ctxt==EGL_NO_CONTEXT, "EGLContext creation failed");
+ return ctxt;
+}
- {
- // initialize the main display
- // TODO: initialize all displays
- DisplayHardware* const hw = new DisplayHardware(this, dpy);
- mDisplayHardwares[0] = hw;
+void SurfaceFlinger::initializeGL(EGLDisplay display, EGLSurface surface) {
+ EGLBoolean result = eglMakeCurrent(display, surface, surface, mEGLContext);
+ if (!result) {
+ ALOGE("Couldn't create a working GLES context. check logs. exiting...");
+ exit(0);
}
- // create the shared control-block
- mServerHeap = new MemoryHeapBase(4096,
- MemoryHeapBase::READ_ONLY, "SurfaceFlinger read-only heap");
- ALOGE_IF(mServerHeap==0, "can't create shared memory dealer");
+ GLExtensions& extensions(GLExtensions::getInstance());
+ extensions.initWithGLStrings(
+ glGetString(GL_VENDOR),
+ glGetString(GL_RENDERER),
+ glGetString(GL_VERSION),
+ glGetString(GL_EXTENSIONS),
+ eglQueryString(display, EGL_VENDOR),
+ eglQueryString(display, EGL_VERSION),
+ eglQueryString(display, EGL_EXTENSIONS));
- mServerCblk = static_cast<surface_flinger_cblk_t*>(mServerHeap->getBase());
- ALOGE_IF(mServerCblk==0, "can't get to shared control block's address");
+ EGLint w, h;
+ eglQuerySurface(display, surface, EGL_WIDTH, &w);
+ eglQuerySurface(display, surface, EGL_HEIGHT, &h);
- new(mServerCblk) surface_flinger_cblk_t;
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
+ glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
- // initialize primary screen
- // (other display should be initialized in the same manner, but
- // asynchronously, as they could come and go. None of this is supported
- // yet).
- const DisplayHardware& hw(getDefaultDisplayHardware());
- const uint32_t w = hw.getWidth();
- const uint32_t h = hw.getHeight();
- const uint32_t f = hw.getFormat();
- hw.makeCurrent();
-
- // initialize the shared control block
- mServerCblk->connected |= 1<<dpy;
- display_cblk_t* dcblk = mServerCblk->displays + dpy;
- memset(dcblk, 0, sizeof(display_cblk_t));
- dcblk->w = w; // XXX: plane.getWidth();
- dcblk->h = h; // XXX: plane.getHeight();
- dcblk->format = f;
- dcblk->orientation = ISurfaceComposer::eOrientationDefault;
- dcblk->xdpi = hw.getDpiX();
- dcblk->ydpi = hw.getDpiY();
- dcblk->fps = hw.getRefreshRate();
- dcblk->density = hw.getDensity();
-
- // Initialize OpenGL|ES
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glPixelStorei(GL_PACK_ALIGNMENT, 4);
glEnableClientState(GL_VERTEX_ARRAY);
@@ -257,6 +297,12 @@
glDisable(GL_DITHER);
glDisable(GL_CULL_FACE);
+ struct pack565 {
+ inline uint16_t operator() (int r, int g, int b) const {
+ return (r<<11)|(g<<5)|b;
+ }
+ } pack565;
+
const uint16_t g0 = pack565(0x0F,0x1F,0x0F);
const uint16_t g1 = pack565(0x17,0x2f,0x17);
const uint16_t wormholeTexData[4] = { g0, g1, g1, g0 };
@@ -285,15 +331,77 @@
// put the origin in the left-bottom corner
glOrthof(0, w, 0, h, 0, 1); // l=0, r=w ; b=0, t=h
+ // print some debugging info
+ EGLint r,g,b,a;
+ eglGetConfigAttrib(display, mEGLConfig, EGL_RED_SIZE, &r);
+ eglGetConfigAttrib(display, mEGLConfig, EGL_GREEN_SIZE, &g);
+ eglGetConfigAttrib(display, mEGLConfig, EGL_BLUE_SIZE, &b);
+ eglGetConfigAttrib(display, mEGLConfig, EGL_ALPHA_SIZE, &a);
+ ALOGI("EGL informations:");
+ ALOGI("vendor : %s", extensions.getEglVendor());
+ ALOGI("version : %s", extensions.getEglVersion());
+ ALOGI("extensions: %s", extensions.getEglExtension());
+ ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported");
+ ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, mEGLConfig);
+ ALOGI("OpenGL ES informations:");
+ ALOGI("vendor : %s", extensions.getVendor());
+ ALOGI("renderer : %s", extensions.getRenderer());
+ ALOGI("version : %s", extensions.getVersion());
+ ALOGI("extensions: %s", extensions.getExtension());
+ ALOGI("GL_MAX_TEXTURE_SIZE = %d", mMaxTextureSize);
+ ALOGI("GL_MAX_VIEWPORT_DIMS = %d x %d", mMaxViewportDims[0], mMaxViewportDims[1]);
+}
+
+surface_flinger_cblk_t* SurfaceFlinger::getControlBlock() const {
+ return mServerCblk;
+}
+
+status_t SurfaceFlinger::readyToRun()
+{
+ ALOGI( "SurfaceFlinger's main thread ready to run. "
+ "Initializing graphics H/W...");
+
+ // create the shared control-block
+ mServerHeap = new MemoryHeapBase(4096,
+ MemoryHeapBase::READ_ONLY, "SurfaceFlinger read-only heap");
+ ALOGE_IF(mServerHeap==0, "can't create shared memory dealer");
+ mServerCblk = static_cast<surface_flinger_cblk_t*>(mServerHeap->getBase());
+ ALOGE_IF(mServerCblk==0, "can't get to shared control block's address");
+ new(mServerCblk) surface_flinger_cblk_t;
+
+
+ // initialize EGL
+ EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglInitialize(display, NULL, NULL);
+
+ // Initialize the main display
+ // create native window to main display
+ sp<FramebufferSurface> anw = FramebufferSurface::create();
+ ANativeWindow* const window = anw.get();
+ if (!window) {
+ ALOGE("Display subsystem failed to initialize. check logs. exiting...");
+ exit(0);
+ }
+
+ // initialize the config and context
+ int format;
+ window->query(window, NATIVE_WINDOW_FORMAT, &format);
+ mEGLConfig = selectEGLConfig(display, format);
+ mEGLContext = createGLContext(display, mEGLConfig);
+
+ // initialize our main display hardware
+ DisplayHardware* const hw = new DisplayHardware(this, 0, anw, mEGLConfig);
+ mDisplayHardwares[0] = hw;
+
+ // initialize OpenGL ES
+ EGLSurface surface = hw->getEGLSurface();
+ initializeGL(display, surface);
// start the EventThread
mEventThread = new EventThread(this);
mEventQueue.setEventThread(mEventThread);
- /*
- * We're now ready to accept clients...
- */
-
+ // We're now ready to accept clients...
mReadyToRunBarrier.open();
// start boot animation
@@ -308,6 +416,15 @@
property_set("ctl.start", "bootanim");
}
+uint32_t SurfaceFlinger::getMaxTextureSize() const {
+ return mMaxTextureSize;
+}
+
+uint32_t SurfaceFlinger::getMaxViewportDims() const {
+ return mMaxViewportDims[0] < mMaxViewportDims[1] ?
+ mMaxViewportDims[0] : mMaxViewportDims[1];
+}
+
// ----------------------------------------------------------------------------
bool SurfaceFlinger::authenticateSurfaceTexture(
@@ -366,7 +483,7 @@
if (display != NULL) {
stc = new SurfaceTextureClient(display);
result = eglCreateWindowSurface(hw.getEGLDisplay(),
- hw.getEGLConfig(), (EGLNativeWindowType)stc.get(), NULL);
+ mEGLConfig, (EGLNativeWindowType)stc.get(), NULL);
ALOGE_IF(result == EGL_NO_SURFACE,
"eglCreateWindowSurface failed (ISurfaceTexture=%p)",
display.get());