Merge "Watch for SurfaceFlinger death" into jb-mr1-dev
diff --git a/cmds/dumpstate/utils.c b/cmds/dumpstate/utils.c
index da00846..cfd7483 100644
--- a/cmds/dumpstate/utils.c
+++ b/cmds/dumpstate/utils.c
@@ -41,6 +41,7 @@
/* list of native processes to include in the native dumps */
static const char* native_processes_to_dump[] = {
+ "/system/bin/drmserver",
"/system/bin/mediaserver",
"/system/bin/sdcard",
"/system/bin/surfaceflinger",
diff --git a/include/gui/ConsumerBase.h b/include/gui/ConsumerBase.h
index a0ddca8..68cce5a 100644
--- a/include/gui/ConsumerBase.h
+++ b/include/gui/ConsumerBase.h
@@ -152,7 +152,14 @@
// it is overridden the derived class's implementation must call
// ConsumerBase::acquireBufferLocked.
virtual status_t releaseBufferLocked(int buf, EGLDisplay display,
- EGLSyncKHR eglFence, const sp<Fence>& fence);
+ EGLSyncKHR eglFence);
+
+ // addReleaseFence adds the sync points associated with a fence to the set
+ // of sync points that must be reached before the buffer in the given slot
+ // may be used after the slot has been released. This should be called by
+ // derived classes each time some asynchronous work is kicked off that
+ // references the buffer.
+ status_t addReleaseFence(int slot, const sp<Fence>& fence);
// Slot contains the information and object references that
// ConsumerBase maintains about a BufferQueue buffer slot.
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 2570cd9..6e5a478 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -77,6 +77,9 @@
//
// This call may only be made while the OpenGL ES context to which the
// target texture belongs is bound to the calling thread.
+ //
+ // After calling this method the doGLFenceWait method must be called
+ // before issuing OpenGL ES commands that access the texture contents.
status_t updateTexImage();
// setReleaseFence stores a fence file descriptor that will signal when the
@@ -154,6 +157,12 @@
// ready to be read from.
sp<Fence> getCurrentFence() const;
+ // doGLFenceWait inserts a wait command into the OpenGL ES command stream
+ // to ensure that it is safe for future OpenGL ES commands to access the
+ // current texture buffer. This must be called each time updateTexImage
+ // is called before issuing OpenGL ES commands that access the texture.
+ status_t doGLFenceWait() const;
+
// isSynchronousMode returns whether the SurfaceTexture is currently in
// synchronous mode.
bool isSynchronousMode() const;
@@ -220,7 +229,7 @@
// releaseBufferLocked overrides the ConsumerBase method to update the
// mEglSlots array in addition to the ConsumerBase.
virtual status_t releaseBufferLocked(int buf, EGLDisplay display,
- EGLSyncKHR eglFence, const sp<Fence>& fence);
+ EGLSyncKHR eglFence);
static bool isExternalFormat(uint32_t format);
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
index 57df39c..74b684f 100644
--- a/libs/gui/BufferItemConsumer.cpp
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -82,8 +82,10 @@
Mutex::Autolock _l(mMutex);
+ err = addReleaseFence(item.mBuf, releaseFence);
+
err = releaseBufferLocked(item.mBuf, EGL_NO_DISPLAY,
- EGL_NO_SYNC_KHR, releaseFence);
+ EGL_NO_SYNC_KHR);
if (err != OK) {
BI_LOGE("Failed to release buffer: %s (%d)",
strerror(-err), err);
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 17bbfd1..fd2d1cc 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -185,15 +185,40 @@
mSlots[item->mBuf].mGraphicBuffer = item->mGraphicBuffer;
}
+ mSlots[item->mBuf].mFence = item->mFence;
+
CB_LOGV("acquireBufferLocked: -> slot=%d", item->mBuf);
return OK;
}
+status_t ConsumerBase::addReleaseFence(int slot, const sp<Fence>& fence) {
+ CB_LOGV("addReleaseFence: slot=%d", slot);
+
+ if (!mSlots[slot].mFence.get()) {
+ mSlots[slot].mFence = fence;
+ } else {
+ sp<Fence> mergedFence = Fence::merge(
+ String8("ConsumerBase merged release"),
+ mSlots[slot].mFence, fence);
+ if (!mergedFence.get()) {
+ CB_LOGE("failed to merge release fences");
+ // synchronization is broken, the best we can do is hope fences
+ // signal in order so the new fence will act like a union
+ mSlots[slot].mFence = fence;
+ return BAD_VALUE;
+ }
+ mSlots[slot].mFence = mergedFence;
+ }
+
+ return OK;
+}
+
status_t ConsumerBase::releaseBufferLocked(int slot, EGLDisplay display,
- EGLSyncKHR eglFence, const sp<Fence>& fence) {
+ EGLSyncKHR eglFence) {
CB_LOGV("releaseBufferLocked: slot=%d", slot);
- status_t err = mBufferQueue->releaseBuffer(slot, display, eglFence, fence);
+ status_t err = mBufferQueue->releaseBuffer(slot, display, eglFence,
+ mSlots[slot].mFence);
if (err == BufferQueue::STALE_BUFFER_SLOT) {
freeBufferLocked(slot);
}
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp
index fc4a854..e1a2838 100644
--- a/libs/gui/CpuConsumer.cpp
+++ b/libs/gui/CpuConsumer.cpp
@@ -134,7 +134,7 @@
CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__, slotIndex);
return err;
}
- releaseBufferLocked(slotIndex, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE);
+ releaseBufferLocked(slotIndex, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
mCurrentLockedBuffers--;
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 975eb23..36a2af7 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -39,6 +39,30 @@
#include <utils/String8.h>
#include <utils/Trace.h>
+// This compile option makes SurfaceTexture use the
+// EGL_ANDROID_native_fence_sync extension to create Android native fences to
+// signal when all GLES reads for a given buffer have completed. It is not
+// compatible with using the EGL_KHR_fence_sync extension for the same
+// purpose.
+#ifdef USE_NATIVE_FENCE_SYNC
+#ifdef USE_FENCE_SYNC
+#error "USE_NATIVE_FENCE_SYNC and USE_FENCE_SYNC are incompatible"
+#endif
+static const bool useNativeFenceSync = true;
+#else
+static const bool useNativeFenceSync = false;
+#endif
+
+// This compile option makes SurfaceTexture use the EGL_ANDROID_sync_wait
+// extension to insert server-side waits into the GLES command stream. This
+// feature requires the EGL_ANDROID_native_fence_sync and
+// EGL_ANDROID_wait_sync extensions.
+#ifdef USE_WAIT_SYNC
+static const bool useWaitSync = true;
+#else
+static const bool useWaitSync = false;
+#endif
+
// This compile option makes SurfaceTexture use the EGL_KHR_fence_sync extension
// to synchronize access to the buffers. It will cause dequeueBuffer to stall,
// waiting for the GL reads for the buffer being dequeued to complete before
@@ -172,9 +196,9 @@
}
status_t SurfaceTexture::releaseBufferLocked(int buf, EGLDisplay display,
- EGLSyncKHR eglFence, const sp<Fence>& fence) {
+ EGLSyncKHR eglFence) {
status_t err = ConsumerBase::releaseBufferLocked(buf, mEglDisplay,
- eglFence, fence);
+ eglFence);
mEglSlots[mCurrentTexture].mEglFence = EGL_NO_SYNC_KHR;
@@ -229,7 +253,7 @@
// not accept this buffer. this is used by SurfaceFlinger to
// reject buffers which have the wrong size
if (rejecter && rejecter->reject(mSlots[buf].mGraphicBuffer, item)) {
- releaseBufferLocked(buf, dpy, EGL_NO_SYNC_KHR, item.mFence);
+ releaseBufferLocked(buf, dpy, EGL_NO_SYNC_KHR);
glBindTexture(mTexTarget, mTexName);
return NO_ERROR;
}
@@ -256,7 +280,7 @@
if (err != NO_ERROR) {
// Release the buffer we just acquired. It's not safe to
// release the old buffer, so instead we just drop the new frame.
- releaseBufferLocked(buf, dpy, EGL_NO_SYNC_KHR, item.mFence);
+ releaseBufferLocked(buf, dpy, EGL_NO_SYNC_KHR);
return err;
}
@@ -268,8 +292,7 @@
// release old buffer
if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
status_t status = releaseBufferLocked(mCurrentTexture, dpy,
- mEglSlots[mCurrentTexture].mEglFence,
- mSlots[mCurrentTexture].mFence);
+ mEglSlots[mCurrentTexture].mEglFence);
if (status != NO_ERROR && status != BufferQueue::STALE_BUFFER_SLOT) {
ST_LOGE("updateTexImage: failed to release buffer: %s (%d)",
strerror(-status), status);
@@ -304,20 +327,10 @@
sp<Fence> fence(new Fence(fenceFd));
if (fenceFd == -1 || mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT)
return;
- if (!mSlots[mCurrentTexture].mFence.get()) {
- mSlots[mCurrentTexture].mFence = fence;
- } else {
- sp<Fence> mergedFence = Fence::merge(
- String8("SurfaceTexture merged release"),
- mSlots[mCurrentTexture].mFence, fence);
- if (!mergedFence.get()) {
- ST_LOGE("failed to merge release fences");
- // synchronization is broken, the best we can do is hope fences
- // signal in order so the new fence will act like a union
- mSlots[mCurrentTexture].mFence = fence;
- return;
- }
- mSlots[mCurrentTexture].mFence = mergedFence;
+ status_t err = addReleaseFence(mCurrentTexture, fence);
+ if (err != OK) {
+ ST_LOGE("setReleaseFence: failed to add the fence: %s (%d)",
+ strerror(-err), err);
}
}
@@ -454,36 +467,61 @@
status_t SurfaceTexture::syncForReleaseLocked(EGLDisplay dpy) {
ST_LOGV("syncForReleaseLocked");
- if (mUseFenceSync && mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
- EGLSyncKHR fence = mEglSlots[mCurrentTexture].mEglFence;
- if (fence != EGL_NO_SYNC_KHR) {
- // There is already a fence for the current slot. We need to wait
- // on that before replacing it with another fence to ensure that all
- // outstanding buffer accesses have completed before the producer
- // accesses it.
- EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
- if (result == EGL_FALSE) {
- ST_LOGE("syncForReleaseLocked: error waiting for previous "
- "fence: %#x", eglGetError());
+ if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
+ if (useNativeFenceSync) {
+ EGLSyncKHR sync = eglCreateSyncKHR(dpy,
+ EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
+ if (sync == EGL_NO_SYNC_KHR) {
+ ST_LOGE("syncForReleaseLocked: error creating EGL fence: %#x",
+ eglGetError());
return UNKNOWN_ERROR;
- } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
- ST_LOGE("syncForReleaseLocked: timeout waiting for previous "
- "fence");
- return TIMED_OUT;
}
- eglDestroySyncKHR(dpy, fence);
- }
+ glFlush();
+ int fenceFd = eglDupNativeFenceFDANDROID(dpy, sync);
+ eglDestroySyncKHR(dpy, sync);
+ if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+ ST_LOGE("syncForReleaseLocked: error dup'ing native fence "
+ "fd: %#x", eglGetError());
+ return UNKNOWN_ERROR;
+ }
+ sp<Fence> fence(new Fence(fenceFd));
+ status_t err = addReleaseFence(mCurrentTexture, fence);
+ if (err != OK) {
+ ST_LOGE("syncForReleaseLocked: error adding release fence: "
+ "%s (%d)", strerror(-err), err);
+ return err;
+ }
+ } else if (mUseFenceSync) {
+ EGLSyncKHR fence = mEglSlots[mCurrentTexture].mEglFence;
+ if (fence != EGL_NO_SYNC_KHR) {
+ // There is already a fence for the current slot. We need to
+ // wait on that before replacing it with another fence to
+ // ensure that all outstanding buffer accesses have completed
+ // before the producer accesses it.
+ EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
+ if (result == EGL_FALSE) {
+ ST_LOGE("syncForReleaseLocked: error waiting for previous "
+ "fence: %#x", eglGetError());
+ return UNKNOWN_ERROR;
+ } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
+ ST_LOGE("syncForReleaseLocked: timeout waiting for previous "
+ "fence");
+ return TIMED_OUT;
+ }
+ eglDestroySyncKHR(dpy, fence);
+ }
- // Create a fence for the outstanding accesses in the current OpenGL ES
- // context.
- fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);
- if (fence == EGL_NO_SYNC_KHR) {
- ST_LOGE("syncForReleaseLocked: error creating fence: %#x",
- eglGetError());
- return UNKNOWN_ERROR;
+ // Create a fence for the outstanding accesses in the current
+ // OpenGL ES context.
+ fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);
+ if (fence == EGL_NO_SYNC_KHR) {
+ ST_LOGE("syncForReleaseLocked: error creating fence: %#x",
+ eglGetError());
+ return UNKNOWN_ERROR;
+ }
+ glFlush();
+ mEglSlots[mCurrentTexture].mEglFence = fence;
}
- glFlush();
- mEglSlots[mCurrentTexture].mEglFence = fence;
}
return OK;
@@ -698,6 +736,66 @@
return mCurrentFence;
}
+status_t SurfaceTexture::doGLFenceWait() const {
+ Mutex::Autolock lock(mMutex);
+
+ EGLDisplay dpy = eglGetCurrentDisplay();
+ EGLContext ctx = eglGetCurrentContext();
+
+ if (mEglDisplay != dpy || mEglDisplay == EGL_NO_DISPLAY) {
+ ST_LOGE("doGLFenceWait: invalid current EGLDisplay");
+ return INVALID_OPERATION;
+ }
+
+ if (mEglContext != ctx || mEglContext == EGL_NO_CONTEXT) {
+ ST_LOGE("doGLFenceWait: invalid current EGLContext");
+ return INVALID_OPERATION;
+ }
+
+ if (mCurrentFence != NULL) {
+ if (useWaitSync) {
+ // Create an EGLSyncKHR from the current fence.
+ int fenceFd = mCurrentFence->dup();
+ if (fenceFd == -1) {
+ ST_LOGE("doGLFenceWait: error dup'ing fence fd: %d", errno);
+ return -errno;
+ }
+ EGLint attribs[] = {
+ EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd,
+ EGL_NONE
+ };
+ EGLSyncKHR sync = eglCreateSyncKHR(dpy,
+ EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
+ if (sync == EGL_NO_SYNC_KHR) {
+ close(fenceFd);
+ ST_LOGE("doGLFenceWait: error creating EGL fence: %#x",
+ eglGetError());
+ return UNKNOWN_ERROR;
+ }
+
+ // XXX: The spec draft is inconsistent as to whether this should
+ // return an EGLint or void. Ignore the return value for now, as
+ // it's not strictly needed.
+ eglWaitSyncANDROID(dpy, sync, 0);
+ EGLint eglErr = eglGetError();
+ eglDestroySyncKHR(dpy, sync);
+ if (eglErr != EGL_SUCCESS) {
+ ST_LOGE("doGLFenceWait: error waiting for EGL fence: %#x",
+ eglErr);
+ return UNKNOWN_ERROR;
+ }
+ } else {
+ status_t err = mCurrentFence->wait(Fence::TIMEOUT_NEVER);
+ if (err != NO_ERROR) {
+ ST_LOGE("doGLFenceWait: error waiting for fence: %d", err);
+ return err;
+ }
+ }
+ }
+
+ return NO_ERROR;
+}
+
bool SurfaceTexture::isSynchronousMode() const {
Mutex::Autolock lock(mMutex);
return mBufferQueue->isSynchronousMode();
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 2d41aa7..5cfa0db 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -270,6 +270,30 @@
typedef EGLBoolean (EGLAPIENTRYP PFEGLAWAKENPROCESSIMGPROC)(void);
#endif
+/* EGL_ANDROID_native_fence_sync
+ */
+#ifndef EGL_ANDROID_native_fence_sync
+#define EGL_ANDROID_native_fence_sync 1
+#define EGL_SYNC_NATIVE_FENCE_ANDROID 0x3144
+#define EGL_SYNC_NATIVE_FENCE_FD_ANDROID 0x3145
+#define EGL_NO_NATIVE_FENCE_FD_ANDROID -1
+#define EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID 0x3146
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLint EGLAPIENTRY eglDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSyncKHR sync);
+#endif
+typedef EGLint (EGLAPIENTRYP PFNEGLDUPNATIVEFENCEFDANDROID) (EGLDisplay dpy, EGLSyncKHR sync);
+#endif
+
+/* EGL_ANDROID_wait_sync
+ */
+#ifndef EGL_ANDROID_wait_sync
+#define EGL_ANDROID_wait_sync
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLint EGLAPIENTRY eglWaitSyncANDROID(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags);
+#endif
+typedef EGLint (EGLAPIENTRYP PFNEGLWAITSYNCANDROID) (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags);
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 1bc4eb7..91b4567 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -652,6 +652,8 @@
// These extensions should not be exposed to applications. They're used
// internally by the Android EGL layer.
if (!strcmp(procname, "eglSetBlobCacheFuncsANDROID") ||
+ !strcmp(procname, "eglDupNativeFenceFDANDROID") ||
+ !strcmp(procname, "eglWaitSyncANDROID") ||
!strcmp(procname, "eglHibernateProcessIMG") ||
!strcmp(procname, "eglAwakenProcessIMG")) {
return NULL;
@@ -1190,7 +1192,35 @@
// ANDROID extensions
// ----------------------------------------------------------------------------
-/* ANDROID extensions entry-point go here */
+EGLint eglDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSyncKHR sync)
+{
+ clearError();
+
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_NO_NATIVE_FENCE_FD_ANDROID;
+
+ EGLint result = EGL_NO_NATIVE_FENCE_FD_ANDROID;
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglDupNativeFenceFDANDROID) {
+ result = cnx->egl.eglDupNativeFenceFDANDROID(dp->disp.dpy, sync);
+ }
+ return result;
+}
+
+EGLint eglWaitSyncANDROID(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags)
+{
+ clearError();
+
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_NO_NATIVE_FENCE_FD_ANDROID;
+
+ EGLint result = EGL_FALSE;
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglWaitSyncANDROID) {
+ result = cnx->egl.eglWaitSyncANDROID(dp->disp.dpy, sync, flags);
+ }
+ return result;
+}
// ----------------------------------------------------------------------------
// NVIDIA extensions
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 80072ab..371df43 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -59,6 +59,7 @@
// extensions not exposed to applications but used by the ANDROID system
// "EGL_ANDROID_recordable " // mandatory
// "EGL_ANDROID_blob_cache " // strongly recommended
+// "EGL_ANDROID_native_fence_sync " // strongly recommended
// "EGL_IMG_hibernate_process " // optional
extern void initEglTraceLevel();
diff --git a/opengl/libs/EGL/egl_entries.in b/opengl/libs/EGL/egl_entries.in
index 9feb716..2ffd417 100644
--- a/opengl/libs/EGL/egl_entries.in
+++ b/opengl/libs/EGL/egl_entries.in
@@ -62,6 +62,8 @@
EGL_ENTRY(EGLBoolean, eglSetSwapRectangleANDROID, EGLDisplay, EGLSurface, EGLint, EGLint, EGLint, EGLint)
EGL_ENTRY(EGLClientBuffer, eglGetRenderBufferANDROID, EGLDisplay, EGLSurface)
+EGL_ENTRY(EGLint, eglDupNativeFenceFDANDROID, EGLDisplay, EGLSyncKHR)
+EGL_ENTRY(EGLint, eglWaitSyncANDROID, EGLDisplay, EGLSyncKHR, EGLint)
/* NVIDIA extensions */
diff --git a/opengl/specs/EGL_ANDROID_native_fence_sync.txt b/opengl/specs/EGL_ANDROID_native_fence_sync.txt
index bd1cdda..8273be4 100644
--- a/opengl/specs/EGL_ANDROID_native_fence_sync.txt
+++ b/opengl/specs/EGL_ANDROID_native_fence_sync.txt
@@ -20,7 +20,7 @@
Version
- Version 2, July 23, 2012
+ Version 3, September 4, 2012
Number
@@ -74,7 +74,7 @@
Accepted by the <attrib_list> parameter of eglCreateSyncKHR, and returned
by eglDupNativeFenceFDANDROID in the event of an error:
- EGL_NO_NATIVE_FENCE_ANDROID -1
+ EGL_NO_NATIVE_FENCE_FD_ANDROID -1
Returned in <value> when eglGetSyncAttribKHR is called with <attribute>
EGL_SYNC_CONDITION_KHR:
@@ -90,7 +90,7 @@
object is created. In this case the EGL_SYNC_NATIVE_FENCE_FD_ANDROID
attribute may optionally be specified. If this attribute is specified, it
must be set to either a file descriptor that refers to a native fence
- object or to the value EGL_NO_NATIVE_FENCE_ANDROID.
+ object or to the value EGL_NO_NATIVE_FENCE_FD_ANDROID.
The default values for the EGL native fence sync object attributes are as
follows:
@@ -202,7 +202,7 @@
The command
EGLint eglDupNativeFenceFDANDROID(
- EGLdisplay dpy,
+ EGLDisplay dpy,
EGLSyncKHR sync);
duplicates the file descriptor stored in the
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 7fb1159..5fba3f6 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -33,21 +33,12 @@
#include <ui/GraphicBuffer.h>
#include "DisplayHardware/FramebufferSurface.h"
+#include "DisplayHardware/HWComposer.h"
// ----------------------------------------------------------------------------
namespace android {
// ----------------------------------------------------------------------------
-sp<FramebufferSurface> FramebufferSurface::create() {
- sp<FramebufferSurface> result = new FramebufferSurface();
- if (result->fbDev == NULL) {
- result = NULL;
- }
- return result;
-}
-
-// ----------------------------------------------------------------------------
-
class GraphicBufferAlloc : public BnGraphicBufferAlloc {
public:
GraphicBufferAlloc() { };
@@ -66,36 +57,21 @@
*
*/
-FramebufferSurface::FramebufferSurface():
+FramebufferSurface::FramebufferSurface(HWComposer& hwc) :
ConsumerBase(new BufferQueue(true, new GraphicBufferAlloc())),
- fbDev(0),
mCurrentBufferSlot(-1),
- mCurrentBuffer(0)
+ mCurrentBuffer(0),
+ mHwc(hwc)
{
- hw_module_t const* module;
-
- if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
- int stride;
- int err;
- int i;
- err = framebuffer_open(module, &fbDev);
- ALOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err));
-
- // bail out if we can't initialize the modules
- if (!fbDev)
- return;
-
- mName = "FramebufferSurface";
- mBufferQueue->setConsumerName(mName);
- mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_FB |
- GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER);
- mBufferQueue->setDefaultBufferFormat(fbDev->format);
- mBufferQueue->setDefaultBufferSize(fbDev->width, fbDev->height);
- mBufferQueue->setSynchronousMode(true);
- mBufferQueue->setDefaultMaxBufferCount(NUM_FRAME_BUFFERS);
- } else {
- ALOGE("Couldn't get gralloc module");
- }
+ mName = "FramebufferSurface";
+ mBufferQueue->setConsumerName(mName);
+ mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_FB |
+ GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER);
+ mBufferQueue->setDefaultBufferFormat(mHwc.getFormat(HWC_DISPLAY_PRIMARY));
+ mBufferQueue->setDefaultBufferSize(mHwc.getResolutionX(HWC_DISPLAY_PRIMARY),
+ mHwc.getResolutionY(HWC_DISPLAY_PRIMARY));
+ mBufferQueue->setSynchronousMode(true);
+ mBufferQueue->setDefaultMaxBufferCount(NUM_FRAME_BUFFERS);
}
status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>* buffer) {
@@ -125,7 +101,7 @@
item.mBuf != mCurrentBufferSlot) {
// Release the previous buffer.
err = releaseBufferLocked(mCurrentBufferSlot, EGL_NO_DISPLAY,
- EGL_NO_SYNC_KHR, Fence::NO_FENCE);
+ EGL_NO_SYNC_KHR);
if (err != NO_ERROR && err != BufferQueue::STALE_BUFFER_SLOT) {
ALOGE("error releasing buffer: %s (%d)", strerror(-err), err);
return err;
@@ -145,12 +121,7 @@
return NO_ERROR;
}
-FramebufferSurface::~FramebufferSurface() {
- if (fbDev) {
- framebuffer_close(fbDev);
- }
-}
-
+// Overrides ConsumerBase::onFrameAvailable(), does not call base class impl.
void FramebufferSurface::onFrameAvailable() {
// XXX: The following code is here temporarily as part of the transition
// away from the framebuffer HAL.
@@ -161,7 +132,7 @@
strerror(-err), err);
return;
}
- err = fbDev->post(fbDev, buf->handle);
+ err = mHwc.fbPost(buf->handle);
if (err != NO_ERROR) {
ALOGE("error posting framebuffer: %d", err);
}
@@ -181,19 +152,11 @@
status_t FramebufferSurface::compositionComplete()
{
- if (fbDev->compositionComplete) {
- return fbDev->compositionComplete(fbDev);
- }
- return INVALID_OPERATION;
+ return mHwc.fbCompositionComplete();
}
void FramebufferSurface::dump(String8& result) {
- if (fbDev->common.version >= 1 && fbDev->dump) {
- const size_t SIZE = 4096;
- char buffer[SIZE];
- fbDev->dump(fbDev, buffer, SIZE);
- result.append(buffer);
- }
+ mHwc.fbDump(result);
ConsumerBase::dump(result);
}
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index bfa500b..fd7c520 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -30,13 +30,13 @@
class Rect;
class String8;
+class HWComposer;
// ---------------------------------------------------------------------------
class FramebufferSurface : public ConsumerBase {
public:
-
- static sp<FramebufferSurface> create();
+ FramebufferSurface(HWComposer& hwc);
bool isUpdateOnDemand() const { return false; }
status_t setUpdateRectangle(const Rect& updateRect);
@@ -49,22 +49,12 @@
// BufferQueue. The new buffer is returned in the 'buffer' argument.
status_t nextBuffer(sp<GraphicBuffer>* buffer);
- // FIXME: currently there are information we can only get from the
- // FB HAL, and FB HAL can only be instantiated once on some devices.
- // Eventually this functionality will have to move in HWC or somewhere else.
- const framebuffer_device_t* getFbHal() const {
- return fbDev;
- }
-
private:
- FramebufferSurface();
- virtual ~FramebufferSurface(); // this class cannot be overloaded
+ virtual ~FramebufferSurface() { }; // this class cannot be overloaded
virtual void onFrameAvailable();
virtual void freeBufferLocked(int slotIndex);
- framebuffer_device_t* fbDev;
-
// mCurrentBufferIndex is the slot index of the current buffer or
// INVALID_BUFFER_SLOT to indicate that either there is no current buffer
// or the buffer is not associated with a slot.
@@ -73,6 +63,9 @@
// mCurrentBuffer is the current buffer or NULL to indicate that there is
// no current buffer.
sp<GraphicBuffer> mCurrentBuffer;
+
+ // Hardware composer, owned by SurfaceFlinger.
+ HWComposer& mHwc;
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index dca27ba..75b8ad8 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -90,10 +90,9 @@
HWComposer::HWComposer(
const sp<SurfaceFlinger>& flinger,
- EventHandler& handler,
- framebuffer_device_t const* fbDev)
+ EventHandler& handler)
: mFlinger(flinger),
- mModule(0), mHwc(0), mNumDisplays(1),
+ mFbDev(0), mHwc(0), mNumDisplays(1),
mCBContext(new cb_context),
mEventHandler(handler),
mVSyncCount(0), mDebugForceFakeVSync(false)
@@ -107,71 +106,68 @@
mDebugForceFakeVSync = atoi(value);
bool needVSyncThread = true;
- int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule);
- ALOGW_IF(err, "%s module not found", HWC_HARDWARE_MODULE_ID);
- if (err == 0) {
- err = hwc_open_1(mModule, &mHwc);
- ALOGE_IF(err, "%s device failed to initialize (%s)",
- HWC_HARDWARE_COMPOSER, strerror(-err));
- if (err == 0) {
- if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_0) ||
- hwcHeaderVersion(mHwc) < MIN_HWC_HEADER_VERSION ||
- hwcHeaderVersion(mHwc) > HWC_HEADER_VERSION) {
- ALOGE("%s device version %#x unsupported, will not be used",
- HWC_HARDWARE_COMPOSER, mHwc->common.version);
- hwc_close_1(mHwc);
- mHwc = NULL;
- }
+
+ // Note: some devices may insist that the FB HAL be opened before HWC.
+ loadFbHalModule();
+ loadHwcModule();
+
+ if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1) && !mFbDev) {
+ ALOGE("ERROR: failed to open framebuffer, aborting");
+ // FB mandatory on <= 1.0, give up
+ abort();
+ }
+
+ if (mHwc) {
+ ALOGI("Using %s version %u.%u", HWC_HARDWARE_COMPOSER,
+ (hwcApiVersion(mHwc) >> 24) & 0xff,
+ (hwcApiVersion(mHwc) >> 16) & 0xff);
+ if (mHwc->registerProcs) {
+ mCBContext->hwc = this;
+ mCBContext->procs.invalidate = &hook_invalidate;
+ mCBContext->procs.vsync = &hook_vsync;
+ if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
+ mCBContext->procs.hotplug = &hook_hotplug;
+ else
+ mCBContext->procs.hotplug = NULL;
+ memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero));
+ mHwc->registerProcs(mHwc, &mCBContext->procs);
}
- if (mHwc) {
- ALOGI("Using %s version %u.%u", HWC_HARDWARE_COMPOSER,
- (hwcApiVersion(mHwc) >> 24) & 0xff,
- (hwcApiVersion(mHwc) >> 16) & 0xff);
- if (mHwc->registerProcs) {
- mCBContext->hwc = this;
- mCBContext->procs.invalidate = &hook_invalidate;
- mCBContext->procs.vsync = &hook_vsync;
- if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
- mCBContext->procs.hotplug = &hook_hotplug;
- else
- mCBContext->procs.hotplug = NULL;
- memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero));
- mHwc->registerProcs(mHwc, &mCBContext->procs);
- }
+ // don't need a vsync thread if we have a hardware composer
+ needVSyncThread = false;
+ // always turn vsync off when we start
+ mHwc->eventControl(mHwc, HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0);
- // always turn vsync off when we start
- needVSyncThread = false;
- mHwc->eventControl(mHwc, HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0);
+ // these IDs are always reserved
+ for (size_t i=0 ; i<HWC_NUM_DISPLAY_TYPES ; i++) {
+ mAllocatedDisplayIDs.markBit(i);
+ }
- // these IDs are always reserved
- for (size_t i=0 ; i<HWC_NUM_DISPLAY_TYPES ; i++) {
- mAllocatedDisplayIDs.markBit(i);
- }
-
- // the number of displays we actually have depends on the
- // hw composer version
- if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_2)) {
- // 1.2 adds support for virtual displays
- mNumDisplays = MAX_DISPLAYS;
- } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
- // 1.1 adds support for multiple displays
- mNumDisplays = HWC_NUM_DISPLAY_TYPES;
- } else {
- mNumDisplays = 1;
- }
+ // the number of displays we actually have depends on the
+ // hw composer version
+ if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_2)) {
+ // 1.2 adds support for virtual displays
+ mNumDisplays = MAX_DISPLAYS;
+ } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
+ // 1.1 adds support for multiple displays
+ mNumDisplays = HWC_NUM_DISPLAY_TYPES;
+ } else {
+ mNumDisplays = 1;
}
}
- if (fbDev) {
+ if (mFbDev) {
ALOG_ASSERT(!(mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)),
"should only have fbdev if no hwc or hwc is 1.0");
DisplayData& disp(mDisplayData[HWC_DISPLAY_PRIMARY]);
- disp.xdpi = fbDev->xdpi;
- disp.ydpi = fbDev->ydpi;
+ disp.xres = mFbDev->width;
+ disp.yres = mFbDev->height;
+ disp.format = mFbDev->format;
+ disp.xdpi = mFbDev->xdpi;
+ disp.ydpi = mFbDev->ydpi;
if (disp.refresh == 0) {
- disp.refresh = nsecs_t(1e9 / fbDev->fps);
+ disp.refresh = nsecs_t(1e9 / mFbDev->fps);
ALOGW("getting VSYNC period from fb HAL: %lld", disp.refresh);
}
if (disp.refresh == 0) {
@@ -197,9 +193,57 @@
if (mHwc) {
hwc_close_1(mHwc);
}
+ if (mFbDev) {
+ framebuffer_close(mFbDev);
+ }
delete mCBContext;
}
+// Load and prepare the hardware composer module. Sets mHwc.
+void HWComposer::loadHwcModule()
+{
+ hw_module_t const* module;
+
+ if (hw_get_module(HWC_HARDWARE_MODULE_ID, &module) != 0) {
+ ALOGE("%s module not found", HWC_HARDWARE_MODULE_ID);
+ return;
+ }
+
+ int err = hwc_open_1(module, &mHwc);
+ if (err) {
+ ALOGE("%s device failed to initialize (%s)",
+ HWC_HARDWARE_COMPOSER, strerror(-err));
+ return;
+ }
+
+ if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_0) ||
+ hwcHeaderVersion(mHwc) < MIN_HWC_HEADER_VERSION ||
+ hwcHeaderVersion(mHwc) > HWC_HEADER_VERSION) {
+ ALOGE("%s device version %#x unsupported, will not be used",
+ HWC_HARDWARE_COMPOSER, mHwc->common.version);
+ hwc_close_1(mHwc);
+ mHwc = NULL;
+ return;
+ }
+}
+
+// Load and prepare the FB HAL, which uses the gralloc module. Sets mFbDev.
+void HWComposer::loadFbHalModule()
+{
+ hw_module_t const* module;
+
+ if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) != 0) {
+ ALOGE("%s module not found", GRALLOC_HARDWARE_MODULE_ID);
+ return;
+ }
+
+ int err = framebuffer_open(module, &mFbDev);
+ if (err) {
+ ALOGE("framebuffer_open failed (%s)", strerror(-err));
+ return;
+ }
+}
+
status_t HWComposer::initCheck() const {
return mHwc ? NO_ERROR : NO_INIT;
}
@@ -265,6 +309,7 @@
void HWComposer::queryDisplayProperties(int disp) {
ALOG_ASSERT(mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1));
+ // use zero as default value for unspecified attributes
int32_t values[NUM_DISPLAY_ATTRIBUTES - 1];
memset(values, 0, sizeof(values));
@@ -283,12 +328,10 @@
mDisplayData[disp].refresh = nsecs_t(values[i]);
break;
case HWC_DISPLAY_RESOLUTION_X:
- // TODO: we'll probably want to remember this eventually
- w = values[i];
+ mDisplayData[disp].xres = values[i];
break;
case HWC_DISPLAY_RESOLUTION_Y:
- // TODO: we'll probably want to remember this eventually
- h = values[i];
+ mDisplayData[disp].yres = values[i];
break;
case HWC_DISPLAY_DPI_X:
mDisplayData[disp].xdpi = values[i] / 1000.0f;
@@ -336,25 +379,37 @@
return NO_ERROR;
}
-nsecs_t HWComposer::getRefreshPeriod() const {
- return mDisplayData[HWC_DISPLAY_PRIMARY].refresh;
+nsecs_t HWComposer::getRefreshPeriod(int disp) const {
+ return mDisplayData[disp].refresh;
}
-nsecs_t HWComposer::getRefreshTimestamp() const {
+nsecs_t HWComposer::getRefreshTimestamp(int disp) const {
// this returns the last refresh timestamp.
// if the last one is not available, we estimate it based on
// the refresh period and whatever closest timestamp we have.
Mutex::Autolock _l(mLock);
nsecs_t now = systemTime(CLOCK_MONOTONIC);
- return now - ((now - mLastHwVSync) % mDisplayData[HWC_DISPLAY_PRIMARY].refresh);
+ return now - ((now - mLastHwVSync) % mDisplayData[disp].refresh);
}
-float HWComposer::getDpiX() const {
- return mDisplayData[HWC_DISPLAY_PRIMARY].xdpi;
+uint32_t HWComposer::getResolutionX(int disp) const {
+ return mDisplayData[disp].xres;
}
-float HWComposer::getDpiY() const {
- return mDisplayData[HWC_DISPLAY_PRIMARY].ydpi;
+uint32_t HWComposer::getResolutionY(int disp) const {
+ return mDisplayData[disp].yres;
+}
+
+uint32_t HWComposer::getFormat(int disp) const {
+ return mDisplayData[disp].format;
+}
+
+float HWComposer::getDpiX(int disp) const {
+ return mDisplayData[disp].xdpi;
+}
+
+float HWComposer::getDpiY(int disp) const {
+ return mDisplayData[disp].ydpi;
}
void HWComposer::eventControl(int event, int enabled) {
@@ -493,6 +548,30 @@
mDisplayData[id].list->numHwLayers : 0;
}
+int HWComposer::fbPost(buffer_handle_t buffer)
+{
+ return mFbDev->post(mFbDev, buffer);
+}
+
+int HWComposer::fbCompositionComplete()
+{
+ if (mFbDev->compositionComplete) {
+ return mFbDev->compositionComplete(mFbDev);
+ } else {
+ return INVALID_OPERATION;
+ }
+}
+
+void HWComposer::fbDump(String8& result) {
+ if (mFbDev->common.version >= 1 && mFbDev->dump) {
+ const size_t SIZE = 4096;
+ char buffer[SIZE];
+ mFbDev->dump(mFbDev, buffer, SIZE);
+ result.append(buffer);
+ }
+}
+
+
/*
* Helper template to implement a concrete HWCLayer
* This holds the pointer to the concrete hwc layer type
@@ -680,7 +759,7 @@
HWComposer::VSyncThread::VSyncThread(HWComposer& hwc)
: mHwc(hwc), mEnabled(false),
mNextFakeVSync(0),
- mRefreshPeriod(hwc.getRefreshPeriod())
+ mRefreshPeriod(hwc.getRefreshPeriod(HWC_DISPLAY_PRIMARY))
{
}
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index a49a023..4c520b1 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -64,8 +64,7 @@
HWComposer(
const sp<SurfaceFlinger>& flinger,
- EventHandler& handler,
- framebuffer_device_t const* fbDev);
+ EventHandler& handler);
~HWComposer();
@@ -107,6 +106,11 @@
// needed forward declarations
class LayerListIterator;
+ // Forwarding to FB HAL for pre-HWC-1.1 code (see FramebufferSurface).
+ int fbPost(buffer_handle_t buffer);
+ int fbCompositionComplete();
+ void fbDump(String8& result);
+
/*
* Interface to hardware composer's layers functionality.
* This abstracts the HAL interface to layers which can evolve in
@@ -208,10 +212,15 @@
void eventControl(int event, int enabled);
- nsecs_t getRefreshPeriod() const;
- nsecs_t getRefreshTimestamp() const;
- float getDpiX() const;
- float getDpiY() const;
+ // Query display parameters. Pass in a display index (e.g.
+ // HWC_DISPLAY_PRIMARY).
+ nsecs_t getRefreshPeriod(int disp) const;
+ nsecs_t getRefreshTimestamp(int disp) const;
+ uint32_t getResolutionX(int disp) const;
+ uint32_t getResolutionY(int disp) const;
+ uint32_t getFormat(int disp) const;
+ float getDpiX(int disp) const;
+ float getDpiY(int disp) const;
// this class is only used to fake the VSync event on systems that don't
// have it.
@@ -236,6 +245,8 @@
const Vector< sp<LayerBase> >& visibleLayersSortedByZ) const;
private:
+ void loadHwcModule();
+ void loadFbHalModule();
LayerListIterator getLayerIterator(int32_t id, size_t index);
size_t getNumLayers(int32_t id) const;
@@ -261,6 +272,9 @@
~DisplayData() {
free(list);
}
+ uint32_t xres;
+ uint32_t yres;
+ uint32_t format; // pixel format from FB hal, for pre-hwc-1.1
float xdpi;
float ydpi;
nsecs_t refresh;
@@ -271,7 +285,7 @@
};
sp<SurfaceFlinger> mFlinger;
- hw_module_t const* mModule;
+ framebuffer_device_t* mFbDev;
struct hwc_composer_device_1* mHwc;
// invariant: mLists[0] != NULL iff mHwc != NULL
// mLists[i>0] can be NULL. that display is to be ignored
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index f39de4a..75eff9f 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -333,11 +333,9 @@
return;
}
- // TODO: replace this with a server-side wait
- sp<Fence> fence = mSurfaceTexture->getCurrentFence();
- if (fence.get()) {
- status_t err = fence->wait(Fence::TIMEOUT_NEVER);
- ALOGW_IF(err != OK, "Layer::onDraw: failed waiting for fence: %d", err);
+ status_t err = mSurfaceTexture->doGLFenceWait();
+ if (err != OK) {
+ ALOGE("onDraw: failed waiting for fence: %d", err);
// Go ahead and draw the buffer anyway; no matter what we do the screen
// is probably going to have something visibly wrong.
}
@@ -517,7 +515,7 @@
const size_t offset = mFrameLatencyOffset;
mFrameStats[offset].timestamp = mSurfaceTexture->getTimestamp();
mFrameStats[offset].set = systemTime();
- mFrameStats[offset].vsync = hwc.getRefreshTimestamp();
+ mFrameStats[offset].vsync = hwc.getRefreshTimestamp(HWC_DISPLAY_PRIMARY);
mFrameLatencyOffset = (mFrameLatencyOffset + 1) % 128;
mFrameLatencyNeeded = false;
}
@@ -728,7 +726,8 @@
{
LayerBaseClient::dumpStats(result, buffer, SIZE);
const size_t o = mFrameLatencyOffset;
- const nsecs_t period = mFlinger->getHwComposer().getRefreshPeriod();
+ const nsecs_t period =
+ mFlinger->getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
result.appendFormat("%lld\n", period);
for (size_t i=0 ; i<128 ; i++) {
const size_t index = (o+i) % 128;
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index 311d95f..b61770c 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -439,7 +439,7 @@
"layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), crop=(%4d,%4d,%4d,%4d), "
"isOpaque=%1d, needsDithering=%1d, invalidate=%1d, "
"alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n",
- s.z, s.layerStack, s.transform.tx(), s.transform.ty(), s.active.w, s.active.h,
+ s.layerStack, s.z, s.transform.tx(), s.transform.ty(), s.active.w, s.active.h,
s.active.crop.left, s.active.crop.top,
s.active.crop.right, s.active.crop.bottom,
isOpaque(), needsDithering(), contentDirty,
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 08cb345..058ba45 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -366,13 +366,18 @@
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
- // initialize EGL
+ // initialize EGL for the default display
mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(mEGLDisplay, NULL, NULL);
+ // Initialize the H/W composer object. There may or may not be an
+ // actual hardware composer underneath.
+ mHwc = new HWComposer(this,
+ *static_cast<HWComposer::EventHandler *>(this));
+
// Initialize the main display
// create native window to main display
- sp<FramebufferSurface> fbs = FramebufferSurface::create();
+ sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc);
if (fbs == NULL) {
ALOGE("Display subsystem failed to initialize. check logs. exiting...");
exit(0);
@@ -408,11 +413,6 @@
mEventThread = new EventThread(this);
mEventQueue.setEventThread(mEventThread);
- // initialize the H/W composer
- mHwc = new HWComposer(this,
- *static_cast<HWComposer::EventHandler *>(this),
- fbs->getFbHal());
-
// initialize our drawing state
mDrawingState = mCurrentState;
@@ -500,8 +500,8 @@
}
const HWComposer& hwc(getHwComposer());
- float xdpi = hwc.getDpiX();
- float ydpi = hwc.getDpiY();
+ float xdpi = hwc.getDpiX(HWC_DISPLAY_PRIMARY);
+ float ydpi = hwc.getDpiY(HWC_DISPLAY_PRIMARY);
// TODO: Not sure if display density should handled by SF any longer
class Density {
@@ -538,7 +538,7 @@
info->h = hw->getHeight();
info->xdpi = xdpi;
info->ydpi = ydpi;
- info->fps = float(1e9 / hwc.getRefreshPeriod());
+ info->fps = float(1e9 / hwc.getRefreshPeriod(HWC_DISPLAY_PRIMARY));
info->density = density;
info->orientation = hw->getOrientation();
// TODO: this needs to go away (currently needed only by webkit)
@@ -618,6 +618,13 @@
}
void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) {
+ if (mEventThread == NULL) {
+ // This is a temporary workaround for b/7145521. A non-null pointer
+ // does not mean EventThread has finished initializing, so this
+ // is not a correct fix.
+ ALOGW("WARNING: EventThread not started, ignoring vsync");
+ return;
+ }
if (uint32_t(type) < DisplayDevice::NUM_DISPLAY_TYPES) {
// we should only receive DisplayDevice::DisplayType from the vsync callback
const wp<IBinder>& token(mDefaultDisplays[type]);
@@ -977,7 +984,7 @@
|| (state.frame != draw[i].frame))
{
disp->setProjection(state.orientation,
- state.viewport, state.viewport);
+ state.viewport, state.frame);
}
}
}
@@ -996,7 +1003,7 @@
state.type, display, stc, 0, mEGLConfig);
disp->setLayerStack(state.layerStack);
disp->setProjection(state.orientation,
- state.viewport, state.viewport);
+ state.viewport, state.frame);
mDisplays.add(display, disp);
}
}
@@ -1728,6 +1735,8 @@
d.what = DisplayState::eDisplayProjectionChanged;
d.token = mDefaultDisplays[DisplayDevice::DISPLAY_PRIMARY];
d.orientation = DisplayState::eOrientationDefault;
+ d.frame.makeInvalid();
+ d.viewport.makeInvalid();
displays.add(d);
setTransactionState(state, displays, 0);
@@ -1963,7 +1972,7 @@
const sp<const DisplayDevice>& hw(mDisplays[dpy]);
snprintf(buffer, SIZE,
"+ DisplayDevice[%u]\n"
- " id=%x, layerStack=%u, (%4dx%4d), orient=%2d (type=%08x), "
+ " type=%x, layerStack=%u, (%4dx%4d), orient=%2d (type=%08x), "
"flips=%u, secure=%d, numLayers=%u, v:[%d,%d,%d,%d], f:[%d,%d,%d,%d]\n",
dpy,
hw->getDisplayType(), hw->getLayerStack(),
@@ -2016,9 +2025,9 @@
mLastSwapBufferTime/1000.0,
mLastTransactionTime/1000.0,
mTransactionFlags,
- 1e9 / hwc.getRefreshPeriod(),
- hwc.getDpiX(),
- hwc.getDpiY());
+ 1e9 / hwc.getRefreshPeriod(HWC_DISPLAY_PRIMARY),
+ hwc.getDpiX(HWC_DISPLAY_PRIMARY),
+ hwc.getDpiY(HWC_DISPLAY_PRIMARY));
result.append(buffer);
snprintf(buffer, SIZE, " eglSwapBuffers time: %f us\n",
diff --git a/services/surfaceflinger/Transform.cpp b/services/surfaceflinger/Transform.cpp
index ca3fa6e..aca90e0 100644
--- a/services/surfaceflinger/Transform.cpp
+++ b/services/surfaceflinger/Transform.cpp
@@ -192,7 +192,6 @@
void Transform::transform(float* point, int x, int y) const
{
- const mat33& M(mMatrix);
vec2 v(x, y);
v = transform(v);
point[0] = v[0];