summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmds/dumpstate/dumpstate.c79
-rw-r--r--include/binder/PermissionCache.h1
-rw-r--r--include/gui/BufferQueue.h27
-rw-r--r--include/gui/CpuConsumer.h142
-rw-r--r--include/gui/ISurfaceComposer.h8
-rw-r--r--include/gui/ISurfaceTexture.h10
-rw-r--r--include/gui/SurfaceTexture.h15
-rw-r--r--include/gui/SurfaceTextureClient.h28
-rw-r--r--include/ui/Fence.h95
-rw-r--r--include/ui/FramebufferNativeWindow.h11
-rw-r--r--include/utils/Trace.h3
-rw-r--r--libs/gui/Android.mk12
-rw-r--r--libs/gui/BufferQueue.cpp29
-rw-r--r--libs/gui/CpuConsumer.cpp233
-rw-r--r--libs/gui/ISurfaceComposer.cpp22
-rw-r--r--libs/gui/ISurfaceTexture.cpp17
-rw-r--r--libs/gui/SurfaceTexture.cpp34
-rw-r--r--libs/gui/SurfaceTextureClient.cpp213
-rw-r--r--libs/gui/tests/Android.mk6
-rw-r--r--libs/gui/tests/CpuConsumer_test.cpp503
-rw-r--r--libs/gui/tests/SurfaceTextureClient_test.cpp182
-rw-r--r--libs/gui/tests/SurfaceTexture_test.cpp112
-rw-r--r--libs/gui/tests/Surface_test.cpp13
-rw-r--r--libs/ui/Android.mk6
-rw-r--r--libs/ui/Fence.cpp97
-rw-r--r--libs/ui/FramebufferNativeWindow.cpp53
-rw-r--r--libs/utils/ZipFileRO.cpp4
-rw-r--r--opengl/libagl/Android.mk2
-rw-r--r--opengl/libagl/egl.cpp30
-rw-r--r--opengl/libs/EGL/egl_display.cpp8
-rw-r--r--opengl/libs/GLES_trace/src/gltrace_context.cpp10
-rw-r--r--opengl/libs/GLES_trace/src/gltrace_context.h4
-rw-r--r--opengl/libs/GLES_trace/src/gltrace_fixup.cpp11
-rw-r--r--opengl/specs/EGL_ANDROID_fence_sync.txt213
-rw-r--r--opengl/specs/README5
-rw-r--r--opengl/tests/hwc/hwcColorEquiv.cpp10
-rw-r--r--opengl/tests/hwc/hwcCommit.cpp6
-rw-r--r--opengl/tests/hwc/hwcRects.cpp6
-rw-r--r--opengl/tests/hwc/hwcStress.cpp8
-rw-r--r--opengl/tests/hwc/hwcTestLib.cpp20
-rw-r--r--opengl/tests/hwc/hwcTestLib.h12
-rw-r--r--services/surfaceflinger/Android.mk14
-rw-r--r--services/surfaceflinger/Client.cpp159
-rw-r--r--services/surfaceflinger/Client.h79
-rw-r--r--services/surfaceflinger/DisplayHardware/DisplayHardware.cpp4
-rw-r--r--services/surfaceflinger/DisplayHardware/DisplayHardware.h4
-rw-r--r--services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp78
-rw-r--r--services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp188
-rw-r--r--services/surfaceflinger/DisplayHardware/FramebufferSurface.h71
-rw-r--r--services/surfaceflinger/DisplayHardware/HWComposer.cpp305
-rw-r--r--services/surfaceflinger/DisplayHardware/HWComposer.h152
-rw-r--r--services/surfaceflinger/Layer.cpp40
-rw-r--r--services/surfaceflinger/Layer.h6
-rw-r--r--services/surfaceflinger/LayerBase.cpp43
-rw-r--r--services/surfaceflinger/LayerBase.h8
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp182
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h39
57 files changed, 2921 insertions, 751 deletions
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index 3b28b22..218ff07 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -88,6 +88,7 @@ static void dumpstate() {
dump_file("KERNEL WAKELOCKS", "/proc/wakelocks");
+ dump_file("KERNEL WAKE SOURCES", "/d/wakeup_sources");
dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
run_command("PROCESSES", 10, "ps", "-P", NULL);
@@ -312,6 +313,14 @@ int main(int argc, char *argv[]) {
int use_socket = 0;
int do_fb = 0;
+ if (getuid() != 0) {
+ // Old versions of the adb client would call the
+ // dumpstate command directly. Newer clients
+ // call /system/bin/bugreport instead. If we detect
+ // we're being called incorrectly, then exec the
+ // correct program.
+ return execl("/system/bin/bugreport", "/system/bin/bugreport", NULL);
+ }
ALOGI("begin\n");
signal(SIGPIPE, SIG_IGN);
@@ -356,44 +365,42 @@ int main(int argc, char *argv[]) {
fclose(cmdline);
}
- if (getuid() == 0) {
- if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
- ALOGE("prctl(PR_SET_KEEPCAPS) failed: %s\n", strerror(errno));
- return -1;
- }
+ if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
+ ALOGE("prctl(PR_SET_KEEPCAPS) failed: %s\n", strerror(errno));
+ return -1;
+ }
- /* switch to non-root user and group */
- gid_t groups[] = { AID_LOG, AID_SDCARD_R, AID_SDCARD_RW,
- AID_MOUNT, AID_INET, AID_NET_BW_STATS };
- if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
- ALOGE("Unable to setgroups, aborting: %s\n", strerror(errno));
- return -1;
- }
- if (setgid(AID_SHELL) != 0) {
- ALOGE("Unable to setgid, aborting: %s\n", strerror(errno));
- return -1;
- }
- if (setuid(AID_SHELL) != 0) {
- ALOGE("Unable to setuid, aborting: %s\n", strerror(errno));
- return -1;
- }
+ /* switch to non-root user and group */
+ gid_t groups[] = { AID_LOG, AID_SDCARD_R, AID_SDCARD_RW,
+ AID_MOUNT, AID_INET, AID_NET_BW_STATS };
+ if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
+ ALOGE("Unable to setgroups, aborting: %s\n", strerror(errno));
+ return -1;
+ }
+ if (setgid(AID_SHELL) != 0) {
+ ALOGE("Unable to setgid, aborting: %s\n", strerror(errno));
+ return -1;
+ }
+ if (setuid(AID_SHELL) != 0) {
+ ALOGE("Unable to setuid, aborting: %s\n", strerror(errno));
+ return -1;
+ }
- struct __user_cap_header_struct capheader;
- struct __user_cap_data_struct capdata[2];
- memset(&capheader, 0, sizeof(capheader));
- memset(&capdata, 0, sizeof(capdata));
- capheader.version = _LINUX_CAPABILITY_VERSION_3;
- capheader.pid = 0;
-
- capdata[CAP_TO_INDEX(CAP_SYSLOG)].permitted = CAP_TO_MASK(CAP_SYSLOG);
- capdata[CAP_TO_INDEX(CAP_SYSLOG)].effective = CAP_TO_MASK(CAP_SYSLOG);
- capdata[0].inheritable = 0;
- capdata[1].inheritable = 0;
-
- if (capset(&capheader, &capdata[0]) < 0) {
- ALOGE("capset failed: %s\n", strerror(errno));
- return -1;
- }
+ struct __user_cap_header_struct capheader;
+ struct __user_cap_data_struct capdata[2];
+ memset(&capheader, 0, sizeof(capheader));
+ memset(&capdata, 0, sizeof(capdata));
+ capheader.version = _LINUX_CAPABILITY_VERSION_3;
+ capheader.pid = 0;
+
+ capdata[CAP_TO_INDEX(CAP_SYSLOG)].permitted = CAP_TO_MASK(CAP_SYSLOG);
+ capdata[CAP_TO_INDEX(CAP_SYSLOG)].effective = CAP_TO_MASK(CAP_SYSLOG);
+ capdata[0].inheritable = 0;
+ capdata[1].inheritable = 0;
+
+ if (capset(&capheader, &capdata[0]) < 0) {
+ ALOGE("capset failed: %s\n", strerror(errno));
+ return -1;
}
char path[PATH_MAX], tmp_path[PATH_MAX];
diff --git a/include/binder/PermissionCache.h b/include/binder/PermissionCache.h
index 1171d48..bcdf0c2 100644
--- a/include/binder/PermissionCache.h
+++ b/include/binder/PermissionCache.h
@@ -22,6 +22,7 @@
#include <utils/String16.h>
#include <utils/Singleton.h>
+#include <utils/SortedVector.h>
namespace android {
// ---------------------------------------------------------------------------
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index 1c80d0c..1ea22fd 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -23,6 +23,7 @@
#include <gui/IGraphicBufferAlloc.h>
#include <gui/ISurfaceTexture.h>
+#include <ui/Fence.h>
#include <ui/GraphicBuffer.h>
#include <utils/String8.h>
@@ -96,7 +97,9 @@ public:
// allowSynchronousMode specifies whether or not synchronous mode can be
// enabled.
// bufferCount sets the minimum number of undequeued buffers for this queue
- BufferQueue( bool allowSynchronousMode = true, int bufferCount = MIN_UNDEQUEUED_BUFFERS);
+ BufferQueue(bool allowSynchronousMode = true,
+ int bufferCount = MIN_UNDEQUEUED_BUFFERS,
+ const sp<IGraphicBufferAlloc>& allocator = NULL);
virtual ~BufferQueue();
virtual int query(int what, int* value);
@@ -113,12 +116,18 @@ public:
// pointed to by the buf argument and a status of OK is returned. If no
// slot is available then a status of -EBUSY is returned and buf is
// unmodified.
+ //
+ // The fence parameter will be updated to hold the fence associated with
+ // the buffer. The contents of the buffer must not be overwritten until the
+ // fence signals. If the fence is NULL, the buffer may be written
+ // immediately.
+ //
// The width and height parameters must be no greater than the minimum of
// GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv).
// An error due to invalid dimensions might not be reported until
// updateTexImage() is called.
- virtual status_t dequeueBuffer(int *buf, uint32_t width, uint32_t height,
- uint32_t format, uint32_t usage);
+ virtual status_t dequeueBuffer(int *buf, sp<Fence>& fence,
+ uint32_t width, uint32_t height, uint32_t format, uint32_t usage);
// queueBuffer returns a filled buffer to the BufferQueue. In addition, a
// timestamp must be provided for the buffer. The timestamp is in
@@ -209,9 +218,15 @@ public:
// releaseBuffer releases a buffer slot from the consumer back to the
// BufferQueue pending a fence sync.
//
+ // If releaseBuffer returns STALE_BUFFER_SLOT, then the consumer must free
+ // any references to the just-released buffer that it might have, as if it
+ // had received a onBuffersReleased() call with a mask set for the released
+ // buffer.
+ //
// Note that the dependencies on EGL will be removed once we switch to using
// the Android HW Sync HAL.
- status_t releaseBuffer(int buf, EGLDisplay display, EGLSyncKHR fence);
+ status_t releaseBuffer(int buf, EGLDisplay display, EGLSyncKHR fence,
+ const sp<Fence>& releaseFence);
// consumerConnect connects a consumer to the BufferQueue. Only one
// consumer may be connected, and when that consumer disconnects the
@@ -371,6 +386,10 @@ private:
// on a compile-time option) set to a new sync object in updateTexImage.
EGLSyncKHR mFence;
+ // mReleaseFence is a fence which must signal before the contents of
+ // the buffer associated with this buffer slot may be overwritten.
+ sp<Fence> mReleaseFence;
+
// Indicates whether this buffer has been seen by a consumer yet
bool mAcquireCalled;
diff --git a/include/gui/CpuConsumer.h b/include/gui/CpuConsumer.h
new file mode 100644
index 0000000..a50a1de
--- /dev/null
+++ b/include/gui/CpuConsumer.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_GUI_CPUCONSUMER_H
+#define ANDROID_GUI_CPUCONSUMER_H
+
+#include <gui/BufferQueue.h>
+
+#include <ui/GraphicBuffer.h>
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/threads.h>
+
+#define ANDROID_GRAPHICS_CPUCONSUMER_JNI_ID "mCpuConsumer"
+
+namespace android {
+
+/**
+ * CpuConsumer is a BufferQueue consumer endpoint that allows direct CPU
+ * access to the underlying gralloc buffers provided by BufferQueue. Multiple
+ * buffers may be acquired by it at once, to be used concurrently by the
+ * CpuConsumer owner. Sets gralloc usage flags to be software-read-only.
+ * This queue is synchronous by default.
+ */
+
+class CpuConsumer: public virtual RefBase,
+ protected BufferQueue::ConsumerListener
+{
+ public:
+ struct FrameAvailableListener : public virtual RefBase {
+ // onFrameAvailable() is called each time an additional frame becomes
+ // available for consumption. A new frame queued will always trigger the
+ // callback, whether the queue is empty or not.
+ //
+ // This is called without any lock held and can be called concurrently
+ // by multiple threads.
+ virtual void onFrameAvailable() = 0;
+ };
+
+ struct LockedBuffer {
+ uint8_t *data;
+ uint32_t width;
+ uint32_t height;
+ PixelFormat format;
+ uint32_t stride;
+ Rect crop;
+ uint32_t transform;
+ uint32_t scalingMode;
+ int64_t timestamp;
+ uint64_t frameNumber;
+ };
+
+ // Create a new CPU consumer. The maxLockedBuffers parameter specifies
+ // how many buffers can be locked for user access at the same time.
+ CpuConsumer(uint32_t maxLockedBuffers);
+
+ virtual ~CpuConsumer();
+
+ // set the name of the CpuConsumer that will be used to identify it in
+ // log messages.
+ void setName(const String8& name);
+
+ // Gets the next graphics buffer from the producer and locks it for CPU use,
+ // filling out the passed-in locked buffer structure with the native pointer
+ // and metadata. Returns BAD_VALUE if no new buffer is available, and
+ // INVALID_OPERATION if the maximum number of buffers is already locked.
+ //
+ // Only a fixed number of buffers can be locked at a time, determined by the
+ // construction-time maxLockedBuffers parameter. If INVALID_OPERATION is
+ // returned by lockNextBuffer, then old buffers must be returned to the queue
+ // by calling unlockBuffer before more buffers can be acquired.
+ status_t lockNextBuffer(LockedBuffer *nativeBuffer);
+
+ // Returns a locked buffer to the queue, allowing it to be reused. Since
+ // only a fixed number of buffers may be locked at a time, old buffers must
+ // be released by calling unlockBuffer to ensure new buffers can be acquired by
+ // lockNextBuffer.
+ status_t unlockBuffer(const LockedBuffer &nativeBuffer);
+
+ // setFrameAvailableListener sets the listener object that will be notified
+ // when a new frame becomes available.
+ void setFrameAvailableListener(const sp<FrameAvailableListener>& listener);
+
+ sp<ISurfaceTexture> getProducerInterface() const { return mBufferQueue; }
+ protected:
+
+ // Implementation of the BufferQueue::ConsumerListener interface. These
+ // calls are used to notify the CpuConsumer of asynchronous events in the
+ // BufferQueue.
+ virtual void onFrameAvailable();
+ virtual void onBuffersReleased();
+
+ private:
+ // Free local buffer state
+ status_t freeBufferLocked(int buf);
+
+ // Maximum number of buffers that can be locked at a time
+ uint32_t mMaxLockedBuffers;
+
+ // mName is a string used to identify the SurfaceTexture in log messages.
+ // It can be set by the setName method.
+ String8 mName;
+
+ // mFrameAvailableListener is the listener object that will be called when a
+ // new frame becomes available. If it is not NULL it will be called from
+ // queueBuffer.
+ sp<FrameAvailableListener> mFrameAvailableListener;
+
+ // Underlying buffer queue
+ sp<BufferQueue> mBufferQueue;
+
+ // Array for caching buffers from the buffer queue
+ sp<GraphicBuffer> mBufferSlot[BufferQueue::NUM_BUFFER_SLOTS];
+ // Array for tracking pointers passed to the consumer, matching the
+ // mBufferSlot indexing
+ void *mBufferPointers[BufferQueue::NUM_BUFFER_SLOTS];
+ // Count of currently locked buffers
+ uint32_t mCurrentLockedBuffers;
+
+ // mMutex is the mutex used to prevent concurrent access to the member
+ // variables of CpuConsumer objects. It must be locked whenever the
+ // member variables are accessed.
+ mutable Mutex mMutex;
+};
+
+} // namespace android
+
+#endif // ANDROID_GUI_CPUCONSUMER_H
diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
index 7320e4d..e4e8aa7 100644
--- a/include/gui/ISurfaceComposer.h
+++ b/include/gui/ISurfaceComposer.h
@@ -139,6 +139,12 @@ public:
/* return an IDisplayEventConnection */
virtual sp<IDisplayEventConnection> createDisplayEventConnection() = 0;
+
+ /* triggers screen off and waits for it to complete */
+ virtual void blank() = 0;
+
+ /* triggers screen on and waits for it to complete */
+ virtual void unblank() = 0;
};
// ----------------------------------------------------------------------------
@@ -160,6 +166,8 @@ public:
TURN_ELECTRON_BEAM_ON,
AUTHENTICATE_SURFACE,
CREATE_DISPLAY_EVENT_CONNECTION,
+ BLANK,
+ UNBLANK,
};
virtual status_t onTransact( uint32_t code,
diff --git a/include/gui/ISurfaceTexture.h b/include/gui/ISurfaceTexture.h
index 1e33764..019606a 100644
--- a/include/gui/ISurfaceTexture.h
+++ b/include/gui/ISurfaceTexture.h
@@ -25,6 +25,7 @@
#include <binder/IInterface.h>
+#include <ui/Fence.h>
#include <ui/GraphicBuffer.h>
#include <ui/Rect.h>
@@ -67,8 +68,13 @@ protected:
// in the contents of its associated buffer contents and call queueBuffer.
// If dequeueBuffer return BUFFER_NEEDS_REALLOCATION, the client is
// expected to call requestBuffer immediately.
- virtual status_t dequeueBuffer(int *slot, uint32_t w, uint32_t h,
- uint32_t format, uint32_t usage) = 0;
+ //
+ // The fence parameter will be updated to hold the fence associated with
+ // the buffer. The contents of the buffer must not be overwritten until the
+ // fence signals. If the fence is NULL, the buffer may be written
+ // immediately.
+ virtual status_t dequeueBuffer(int *slot, sp<Fence>& fence,
+ uint32_t w, uint32_t h, uint32_t format, uint32_t usage) = 0;
// queueBuffer indicates that the client has finished filling in the
// contents of the buffer associated with slot and transfers ownership of
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 2635e2f..622724e 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -91,6 +91,14 @@ public:
// target texture belongs is bound to the calling thread.
status_t updateTexImage();
+ // setReleaseFence stores a fence file descriptor that will signal when the
+ // current buffer is no longer being read. This fence will be returned to
+ // the producer when the current buffer is released by updateTexImage().
+ // Multiple fences can be set for a given buffer; they will be merged into
+ // a single union fence. The SurfaceTexture will close the file descriptor
+ // when finished with it.
+ void setReleaseFence(int fenceFd);
+
// setBufferCountServer set the buffer count. If the client has requested
// a buffer count using setBufferCount, the server-buffer count will
// take effect once the client sets the count back to zero.
@@ -349,6 +357,13 @@ private:
// to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based
// on a compile-time option) set to a new sync object in updateTexImage.
EGLSyncKHR mFence;
+
+ // mReleaseFence is a fence which will signal when the buffer
+ // associated with this buffer slot is no longer being used by the
+ // consumer and can be overwritten. The buffer can be dequeued before
+ // the fence signals; the producer is responsible for delaying writes
+ // until it signals.
+ sp<Fence> mReleaseFence;
};
// mEglDisplay is the EGLDisplay with which this SurfaceTexture is currently
diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h
index 8fa85b6..50fd1ba 100644
--- a/include/gui/SurfaceTextureClient.h
+++ b/include/gui/SurfaceTextureClient.h
@@ -61,14 +61,25 @@ private:
void init();
// ANativeWindow hooks
- static int hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
- static int hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
- static int hook_lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ static int hook_cancelBuffer(ANativeWindow* window,
+ ANativeWindowBuffer* buffer, int fenceFd);
+ static int hook_dequeueBuffer(ANativeWindow* window,
+ ANativeWindowBuffer** buffer, int* fenceFd);
static int hook_perform(ANativeWindow* window, int operation, ...);
static int hook_query(const ANativeWindow* window, int what, int* value);
- static int hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ static int hook_queueBuffer(ANativeWindow* window,
+ ANativeWindowBuffer* buffer, int fenceFd);
static int hook_setSwapInterval(ANativeWindow* window, int interval);
+ static int hook_cancelBuffer_DEPRECATED(ANativeWindow* window,
+ ANativeWindowBuffer* buffer);
+ static int hook_dequeueBuffer_DEPRECATED(ANativeWindow* window,
+ ANativeWindowBuffer** buffer);
+ static int hook_lockBuffer_DEPRECATED(ANativeWindow* window,
+ ANativeWindowBuffer* buffer);
+ static int hook_queueBuffer_DEPRECATED(ANativeWindow* window,
+ ANativeWindowBuffer* buffer);
+
int dispatchConnect(va_list args);
int dispatchDisconnect(va_list args);
int dispatchSetBufferCount(va_list args);
@@ -86,14 +97,15 @@ private:
int dispatchUnlockAndPost(va_list args);
protected:
- virtual int cancelBuffer(ANativeWindowBuffer* buffer);
- virtual int dequeueBuffer(ANativeWindowBuffer** buffer);
- virtual int lockBuffer(ANativeWindowBuffer* buffer);
+ virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
+ virtual int cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd);
+ virtual int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd);
virtual int perform(int operation, va_list args);
virtual int query(int what, int* value) const;
- virtual int queueBuffer(ANativeWindowBuffer* buffer);
virtual int setSwapInterval(int interval);
+ virtual int lockBuffer_DEPRECATED(ANativeWindowBuffer* buffer);
+
virtual int connect(int api);
virtual int disconnect(int api);
virtual int setBufferCount(int bufferCount);
diff --git a/include/ui/Fence.h b/include/ui/Fence.h
new file mode 100644
index 0000000..195f2e9
--- /dev/null
+++ b/include/ui/Fence.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_FENCE_H
+#define ANDROID_FENCE_H
+
+#include <stdint.h>
+#include <limits.h>
+#include <sys/types.h>
+
+#include <ui/ANativeObjectBase.h>
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+#include <utils/Flattenable.h>
+#include <utils/String8.h>
+
+struct ANativeWindowBuffer;
+
+namespace android {
+
+// ===========================================================================
+// Fence
+// ===========================================================================
+
+class Fence
+ : public LightRefBase<Fence>, public Flattenable
+{
+public:
+ static const sp<Fence> NO_FENCE;
+
+ // Construct a new Fence object with an invalid file descriptor. This
+ // should be done when the Fence object will be set up by unflattening
+ // serialized data.
+ Fence();
+
+ // Construct a new Fence object to manage a given fence file descriptor.
+ // When the new Fence object is destructed the file descriptor will be
+ // closed.
+ Fence(int fenceFd);
+
+ // wait waits for up to timeout milliseconds for the fence to signal. If
+ // the fence signals then NO_ERROR is returned. If the timeout expires
+ // before the fence signals then -ETIME is returned. A timeout of
+ // TIMEOUT_NEVER may be used to indicate that the call should wait
+ // indefinitely for the fence to signal.
+ int wait(unsigned int timeout);
+
+ // TIMEOUT_NEVER may be passed to the wait method to indicate that it
+ // should wait indefinitely for the fence to signal.
+ enum { TIMEOUT_NEVER = UINT_MAX };
+
+ // merge combines two Fence objects, creating a new Fence object that
+ // becomes signaled when both f1 and f2 are signaled (even if f1 or f2 is
+ // destroyed before it becomes signaled). The name argument specifies the
+ // human-readable name to associated with the new Fence object.
+ static sp<Fence> merge(const String8& name, const sp<Fence>& f1,
+ const sp<Fence>& f2);
+
+ // Flattenable interface
+ size_t getFlattenedSize() const;
+ size_t getFdCount() const;
+ status_t flatten(void* buffer, size_t size,
+ int fds[], size_t count) const;
+ status_t unflatten(void const* buffer, size_t size,
+ int fds[], size_t count);
+
+private:
+ // Only allow instantiation using ref counting.
+ friend class LightRefBase<Fence>;
+ virtual ~Fence();
+
+ // Disallow copying
+ Fence(const Fence& rhs);
+ Fence& operator = (const Fence& rhs);
+ const Fence& operator = (const Fence& rhs) const;
+
+ int mFenceFd;
+};
+
+}; // namespace android
+
+#endif // ANDROID_FENCE_H
diff --git a/include/ui/FramebufferNativeWindow.h b/include/ui/FramebufferNativeWindow.h
index b202b95..e0b14f7 100644
--- a/include/ui/FramebufferNativeWindow.h
+++ b/include/ui/FramebufferNativeWindow.h
@@ -65,12 +65,15 @@ private:
friend class LightRefBase<FramebufferNativeWindow>;
~FramebufferNativeWindow(); // this class cannot be overloaded
static int setSwapInterval(ANativeWindow* window, int interval);
- static int dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
- static int lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
- static int queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ static int dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer, int* fenceFd);
+ static int queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd);
static int query(const ANativeWindow* window, int what, int* value);
static int perform(ANativeWindow* window, int operation, ...);
-
+
+ static int dequeueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer** buffer);
+ static int queueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ static int lockBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer);
+
framebuffer_device_t* fbDev;
alloc_device_t* grDev;
diff --git a/include/utils/Trace.h b/include/utils/Trace.h
index 4219206..e5cc7ec 100644
--- a/include/utils/Trace.h
+++ b/include/utils/Trace.h
@@ -51,7 +51,8 @@
#define ATRACE_TAG_SYNC_MANAGER (1<<7)
#define ATRACE_TAG_AUDIO (1<<8)
#define ATRACE_TAG_VIDEO (1<<9)
-#define ATRACE_TAG_LAST ATRACE_TAG_VIDEO
+#define ATRACE_TAG_CAMERA (1<<10)
+#define ATRACE_TAG_LAST ATRACE_TAG_CAMERA
#define ATRACE_TAG_VALID_MASK ((ATRACE_TAG_LAST - 1) | ATRACE_TAG_LAST)
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
index 8224847..1cda14e 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -21,17 +21,19 @@ LOCAL_SRC_FILES:= \
LayerState.cpp \
Surface.cpp \
SurfaceComposerClient.cpp \
- DummyConsumer.cpp
+ DummyConsumer.cpp \
+ CpuConsumer.cpp
LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libutils \
libbinder \
+ libcutils \
+ libEGL \
+ libGLESv2 \
libhardware \
libhardware_legacy \
+ libsync \
libui \
- libEGL \
- libGLESv2 \
+ libutils \
LOCAL_MODULE:= libgui
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index a0774cf..40e43a1 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -81,7 +81,8 @@ static const char* scalingModeName(int scalingMode) {
}
}
-BufferQueue::BufferQueue( bool allowSynchronousMode, int bufferCount ) :
+BufferQueue::BufferQueue(bool allowSynchronousMode, int bufferCount,
+ const sp<IGraphicBufferAlloc>& allocator) :
mDefaultWidth(1),
mDefaultHeight(1),
mPixelFormat(PIXEL_FORMAT_RGBA_8888),
@@ -105,10 +106,14 @@ BufferQueue::BufferQueue( bool allowSynchronousMode, int bufferCount ) :
mConsumerName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
ST_LOGV("BufferQueue");
- sp<ISurfaceComposer> composer(ComposerService::getComposerService());
- mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
- if (mGraphicBufferAlloc == 0) {
- ST_LOGE("createGraphicBufferAlloc() failed in BufferQueue()");
+ if (allocator == NULL) {
+ sp<ISurfaceComposer> composer(ComposerService::getComposerService());
+ mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
+ if (mGraphicBufferAlloc == 0) {
+ ST_LOGE("createGraphicBufferAlloc() failed in BufferQueue()");
+ }
+ } else {
+ mGraphicBufferAlloc = allocator;
}
}
@@ -289,8 +294,8 @@ status_t BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
return NO_ERROR;
}
-status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
- uint32_t format, uint32_t usage) {
+status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence,
+ uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
ATRACE_CALL();
ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage);
@@ -313,7 +318,6 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
usage |= mConsumerUsageBits;
int found = -1;
- int foundSync = -1;
int dequeuedCount = 0;
bool tryAgain = true;
while (tryAgain) {
@@ -364,7 +368,6 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
// look for a free buffer to give to the client
found = INVALID_BUFFER_SLOT;
- foundSync = INVALID_BUFFER_SLOT;
dequeuedCount = 0;
for (int i = 0; i < mBufferCount; i++) {
const int state = mSlots[i].mBufferState;
@@ -388,7 +391,6 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
bool isOlder = mSlots[i].mFrameNumber <
mSlots[found].mFrameNumber;
if (found < 0 || isOlder) {
- foundSync = i;
found = i;
}
}
@@ -479,6 +481,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
mSlots[buf].mGraphicBuffer = graphicBuffer;
mSlots[buf].mRequestBufferCalled = false;
mSlots[buf].mFence = EGL_NO_SYNC_KHR;
+ mSlots[buf].mReleaseFence.clear();
mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
@@ -486,7 +489,9 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
dpy = mSlots[buf].mEglDisplay;
fence = mSlots[buf].mFence;
+ outFence = mSlots[buf].mReleaseFence;
mSlots[buf].mFence = EGL_NO_SYNC_KHR;
+ mSlots[buf].mReleaseFence.clear();
} // end lock scope
if (fence != EGL_NO_SYNC_KHR) {
@@ -841,6 +846,7 @@ void BufferQueue::freeBufferLocked(int i) {
eglDestroySyncKHR(mSlots[i].mEglDisplay, mSlots[i].mFence);
mSlots[i].mFence = EGL_NO_SYNC_KHR;
}
+ mSlots[i].mReleaseFence.clear();
}
void BufferQueue::freeAllBuffersLocked() {
@@ -891,7 +897,7 @@ status_t BufferQueue::acquireBuffer(BufferItem *buffer) {
}
status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display,
- EGLSyncKHR fence) {
+ EGLSyncKHR fence, const sp<Fence>& releaseFence) {
ATRACE_CALL();
ATRACE_BUFFER_INDEX(buf);
@@ -903,6 +909,7 @@ status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display,
mSlots[buf].mEglDisplay = display;
mSlots[buf].mFence = fence;
+ mSlots[buf].mReleaseFence = releaseFence;
// The buffer can now only be released if its in the acquired state
if (mSlots[buf].mBufferState == BufferSlot::ACQUIRED) {
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp
new file mode 100644
index 0000000..bf2539f
--- /dev/null
+++ b/libs/gui/CpuConsumer.cpp
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "CpuConsumer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <utils/Log.h>
+
+#include <gui/CpuConsumer.h>
+
+#define CC_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define CC_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define CC_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define CC_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define CC_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__)
+
+namespace android {
+
+// Get an ID that's unique within this process.
+static int32_t createProcessUniqueId() {
+ static volatile int32_t globalCounter = 0;
+ return android_atomic_inc(&globalCounter);
+}
+
+CpuConsumer::CpuConsumer(uint32_t maxLockedBuffers) :
+ mMaxLockedBuffers(maxLockedBuffers),
+ mCurrentLockedBuffers(0)
+{
+ mName = String8::format("cc-unnamed-%d-%d", getpid(),
+ createProcessUniqueId());
+
+ for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+ mBufferPointers[i] = NULL;
+ }
+
+ mBufferQueue = new BufferQueue(true);
+
+ wp<BufferQueue::ConsumerListener> listener;
+ sp<BufferQueue::ConsumerListener> proxy;
+ listener = static_cast<BufferQueue::ConsumerListener*>(this);
+ proxy = new BufferQueue::ProxyConsumerListener(listener);
+
+ status_t err = mBufferQueue->consumerConnect(proxy);
+ if (err != NO_ERROR) {
+ ALOGE("CpuConsumer: error connecting to BufferQueue: %s (%d)",
+ strerror(-err), err);
+ } else {
+ mBufferQueue->setSynchronousMode(true);
+ mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_SW_READ_OFTEN);
+ mBufferQueue->setConsumerName(mName);
+ }
+}
+
+CpuConsumer::~CpuConsumer()
+{
+ Mutex::Autolock _l(mMutex);
+ for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+ freeBufferLocked(i);
+ }
+ mBufferQueue->consumerDisconnect();
+ mBufferQueue.clear();
+}
+
+void CpuConsumer::setName(const String8& name) {
+ Mutex::Autolock _l(mMutex);
+ mName = name;
+ mBufferQueue->setConsumerName(name);
+}
+
+status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) {
+ status_t err;
+
+ if (!nativeBuffer) return BAD_VALUE;
+ if (mCurrentLockedBuffers == mMaxLockedBuffers) {
+ return INVALID_OPERATION;
+ }
+
+ BufferQueue::BufferItem b;
+
+ Mutex::Autolock _l(mMutex);
+
+ err = mBufferQueue->acquireBuffer(&b);
+ if (err != OK) {
+ if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
+ return BAD_VALUE;
+ } else {
+ CC_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err);
+ return err;
+ }
+ }
+
+ int buf = b.mBuf;
+
+ if (b.mGraphicBuffer != NULL) {
+ if (mBufferPointers[buf] != NULL) {
+ CC_LOGE("Reallocation of buffer %d while in consumer use!", buf);
+ mBufferQueue->releaseBuffer(buf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR,
+ Fence::NO_FENCE);
+ return BAD_VALUE;
+ }
+ mBufferSlot[buf] = b.mGraphicBuffer;
+ }
+
+ err = mBufferSlot[buf]->lock(
+ GraphicBuffer::USAGE_SW_READ_OFTEN,
+ b.mCrop,
+ &mBufferPointers[buf]);
+
+ if (mBufferPointers[buf] != NULL && err != OK) {
+ CC_LOGE("Unable to lock buffer for CPU reading: %s (%d)", strerror(-err),
+ err);
+ return err;
+ }
+
+ nativeBuffer->data = reinterpret_cast<uint8_t*>(mBufferPointers[buf]);
+ nativeBuffer->width = mBufferSlot[buf]->getWidth();
+ nativeBuffer->height = mBufferSlot[buf]->getHeight();
+ nativeBuffer->format = mBufferSlot[buf]->getPixelFormat();
+ nativeBuffer->stride = mBufferSlot[buf]->getStride();
+
+ nativeBuffer->crop = b.mCrop;
+ nativeBuffer->transform = b.mTransform;
+ nativeBuffer->scalingMode = b.mScalingMode;
+ nativeBuffer->timestamp = b.mTimestamp;
+ nativeBuffer->frameNumber = b.mFrameNumber;
+
+ mCurrentLockedBuffers++;
+
+ return OK;
+}
+
+status_t CpuConsumer::unlockBuffer(const LockedBuffer &nativeBuffer) {
+ Mutex::Autolock _l(mMutex);
+ int buf = 0;
+ status_t err;
+
+ void *bufPtr = reinterpret_cast<void *>(nativeBuffer.data);
+ for (; buf < BufferQueue::NUM_BUFFER_SLOTS; buf++) {
+ if (bufPtr == mBufferPointers[buf]) break;
+ }
+ if (buf == BufferQueue::NUM_BUFFER_SLOTS) {
+ CC_LOGE("%s: Can't find buffer to free", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ mBufferPointers[buf] = NULL;
+ err = mBufferSlot[buf]->unlock();
+ if (err != OK) {
+ CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__, buf);
+ return err;
+ }
+ err = mBufferQueue->releaseBuffer(buf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR,
+ Fence::NO_FENCE);
+ if (err == BufferQueue::STALE_BUFFER_SLOT) {
+ freeBufferLocked(buf);
+ } else if (err != OK) {
+ CC_LOGE("%s: Unable to release graphic buffer %d to queue", __FUNCTION__,
+ buf);
+ return err;
+ }
+
+ mCurrentLockedBuffers--;
+
+ return OK;
+}
+
+void CpuConsumer::setFrameAvailableListener(
+ const sp<FrameAvailableListener>& listener) {
+ CC_LOGV("setFrameAvailableListener");
+ Mutex::Autolock lock(mMutex);
+ mFrameAvailableListener = listener;
+}
+
+
+void CpuConsumer::onFrameAvailable() {
+ CC_LOGV("onFrameAvailable");
+ sp<FrameAvailableListener> listener;
+ { // scope for the lock
+ Mutex::Autolock _l(mMutex);
+ listener = mFrameAvailableListener;
+ }
+
+ if (listener != NULL) {
+ CC_LOGV("actually calling onFrameAvailable");
+ listener->onFrameAvailable();
+ }
+}
+
+void CpuConsumer::onBuffersReleased() {
+ CC_LOGV("onBuffersReleased");
+
+ Mutex::Autolock lock(mMutex);
+
+ uint32_t mask = 0;
+ mBufferQueue->getReleasedBuffers(&mask);
+ for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+ if (mask & (1 << i)) {
+ freeBufferLocked(i);
+ }
+ }
+
+}
+
+status_t CpuConsumer::freeBufferLocked(int buf) {
+ status_t err = OK;
+
+ if (mBufferPointers[buf] != NULL) {
+ CC_LOGW("Buffer %d freed while locked by consumer", buf);
+ mBufferPointers[buf] = NULL;
+ err = mBufferSlot[buf]->unlock();
+ if (err != OK) {
+ CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__, buf);
+ }
+ mCurrentLockedBuffers--;
+ }
+ mBufferSlot[buf] = NULL;
+ return err;
+}
+
+} // namespace android
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 1f1794c..8177e4d 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -193,6 +193,20 @@ public:
result = interface_cast<IDisplayEventConnection>(reply.readStrongBinder());
return result;
}
+
+ virtual void blank()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ remote()->transact(BnSurfaceComposer::BLANK, data, &reply);
+ }
+
+ virtual void unblank()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ remote()->transact(BnSurfaceComposer::UNBLANK, data, &reply);
+ }
};
IMPLEMENT_META_INTERFACE(SurfaceComposer, "android.ui.ISurfaceComposer");
@@ -279,6 +293,14 @@ status_t BnSurfaceComposer::onTransact(
reply->writeStrongBinder(connection->asBinder());
return NO_ERROR;
} break;
+ case BLANK: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ blank();
+ } break;
+ case UNBLANK: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ unblank();
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/ISurfaceTexture.cpp b/libs/gui/ISurfaceTexture.cpp
index 3eb5e7a..c8fef06 100644
--- a/libs/gui/ISurfaceTexture.cpp
+++ b/libs/gui/ISurfaceTexture.cpp
@@ -81,8 +81,8 @@ public:
return result;
}
- virtual status_t dequeueBuffer(int *buf, uint32_t w, uint32_t h,
- uint32_t format, uint32_t usage) {
+ virtual status_t dequeueBuffer(int *buf, sp<Fence>& fence,
+ uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
data.writeInt32(w);
@@ -94,6 +94,12 @@ public:
return result;
}
*buf = reply.readInt32();
+ fence.clear();
+ bool hasFence = reply.readInt32();
+ if (hasFence) {
+ fence = new Fence();
+ reply.read(*fence.get());
+ }
result = reply.readInt32();
return result;
}
@@ -205,8 +211,13 @@ status_t BnSurfaceTexture::onTransact(
uint32_t format = data.readInt32();
uint32_t usage = data.readInt32();
int buf;
- int result = dequeueBuffer(&buf, w, h, format, usage);
+ sp<Fence> fence;
+ int result = dequeueBuffer(&buf, fence, w, h, format, usage);
reply->writeInt32(buf);
+ reply->writeInt32(fence.get() != NULL);
+ if (fence.get() != NULL) {
+ reply->write(*fence.get());
+ }
reply->writeInt32(result);
return NO_ERROR;
} break;
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 55be4bc..8ef885b 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -236,8 +236,10 @@ status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter) {
// not accept this buffer. this is used by SurfaceFlinger to
// reject buffers which have the wrong size
if (rejecter && rejecter->reject(mEGLSlots[buf].mGraphicBuffer, item)) {
- mBufferQueue->releaseBuffer(buf, dpy, mEGLSlots[buf].mFence);
+ mBufferQueue->releaseBuffer(buf, dpy, mEGLSlots[buf].mFence,
+ mEGLSlots[buf].mReleaseFence);
mEGLSlots[buf].mFence = EGL_NO_SYNC_KHR;
+ mEGLSlots[buf].mReleaseFence.clear();
glBindTexture(mTexTarget, mTexName);
return NO_ERROR;
}
@@ -284,8 +286,10 @@ status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter) {
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.
- mBufferQueue->releaseBuffer(buf, dpy, mEGLSlots[buf].mFence);
+ mBufferQueue->releaseBuffer(buf, dpy, mEGLSlots[buf].mFence,
+ mEGLSlots[buf].mReleaseFence);
mEGLSlots[buf].mFence = EGL_NO_SYNC_KHR;
+ mEGLSlots[buf].mReleaseFence.clear();
return err;
}
@@ -297,9 +301,10 @@ status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter) {
// release old buffer
if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
status_t status = mBufferQueue->releaseBuffer(mCurrentTexture, dpy,
- mEGLSlots[mCurrentTexture].mFence);
-
+ mEGLSlots[mCurrentTexture].mFence,
+ mEGLSlots[mCurrentTexture].mReleaseFence);
mEGLSlots[mCurrentTexture].mFence = EGL_NO_SYNC_KHR;
+ mEGLSlots[mCurrentTexture].mReleaseFence.clear();
if (status == BufferQueue::STALE_BUFFER_SLOT) {
freeBufferLocked(mCurrentTexture);
} else if (status != NO_ERROR) {
@@ -328,6 +333,27 @@ status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter) {
return err;
}
+void SurfaceTexture::setReleaseFence(int fenceFd) {
+ if (fenceFd == -1)
+ return;
+ sp<Fence> fence(new Fence(fenceFd));
+ if (!mEGLSlots[mCurrentTexture].mReleaseFence.get()) {
+ mEGLSlots[mCurrentTexture].mReleaseFence = fence;
+ } else {
+ sp<Fence> mergedFence = Fence::merge(
+ String8("SurfaceTexture merged release"),
+ mEGLSlots[mCurrentTexture].mReleaseFence, fence);
+ if (mergedFence.get()) {
+ ALOGE("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
+ mEGLSlots[mCurrentTexture].mReleaseFence = fence;
+ } else {
+ mEGLSlots[mCurrentTexture].mReleaseFence = mergedFence;
+ }
+ }
+}
+
status_t SurfaceTexture::detachFromContext() {
ATRACE_CALL();
ST_LOGV("detachFromContext");
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index 36a81a6..57bc604 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -23,6 +23,8 @@
#include <utils/Log.h>
#include <utils/Trace.h>
+#include <ui/Fence.h>
+
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/SurfaceTexture.h>
@@ -62,11 +64,15 @@ void SurfaceTextureClient::init() {
ANativeWindow::setSwapInterval = hook_setSwapInterval;
ANativeWindow::dequeueBuffer = hook_dequeueBuffer;
ANativeWindow::cancelBuffer = hook_cancelBuffer;
- ANativeWindow::lockBuffer = hook_lockBuffer;
ANativeWindow::queueBuffer = hook_queueBuffer;
ANativeWindow::query = hook_query;
ANativeWindow::perform = hook_perform;
+ ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED;
+ ANativeWindow::cancelBuffer_DEPRECATED = hook_cancelBuffer_DEPRECATED;
+ ANativeWindow::lockBuffer_DEPRECATED = hook_lockBuffer_DEPRECATED;
+ ANativeWindow::queueBuffer_DEPRECATED = hook_queueBuffer_DEPRECATED;
+
const_cast<int&>(ANativeWindow::minSwapInterval) = 0;
const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;
@@ -103,27 +109,54 @@ int SurfaceTextureClient::hook_setSwapInterval(ANativeWindow* window, int interv
}
int SurfaceTextureClient::hook_dequeueBuffer(ANativeWindow* window,
- ANativeWindowBuffer** buffer) {
+ ANativeWindowBuffer** buffer, int* fenceFd) {
SurfaceTextureClient* c = getSelf(window);
- return c->dequeueBuffer(buffer);
+ return c->dequeueBuffer(buffer, fenceFd);
}
int SurfaceTextureClient::hook_cancelBuffer(ANativeWindow* window,
+ ANativeWindowBuffer* buffer, int fenceFd) {
+ SurfaceTextureClient* c = getSelf(window);
+ return c->cancelBuffer(buffer, fenceFd);
+}
+
+int SurfaceTextureClient::hook_queueBuffer(ANativeWindow* window,
+ ANativeWindowBuffer* buffer, int fenceFd) {
+ SurfaceTextureClient* c = getSelf(window);
+ return c->queueBuffer(buffer, fenceFd);
+}
+
+int SurfaceTextureClient::hook_dequeueBuffer_DEPRECATED(ANativeWindow* window,
+ ANativeWindowBuffer** buffer) {
+ SurfaceTextureClient* c = getSelf(window);
+ int fenceFd = -1;
+ int result = c->dequeueBuffer(buffer, &fenceFd);
+ sp<Fence> fence(new Fence(fenceFd));
+ int waitResult = fence->wait(Fence::TIMEOUT_NEVER);
+ if (waitResult != OK) {
+ ALOGE("hook_dequeueBuffer_DEPRECATED: Fence::wait returned an "
+ "error: %d", waitResult);
+ return waitResult;
+ }
+ return result;
+}
+
+int SurfaceTextureClient::hook_cancelBuffer_DEPRECATED(ANativeWindow* window,
ANativeWindowBuffer* buffer) {
SurfaceTextureClient* c = getSelf(window);
- return c->cancelBuffer(buffer);
+ return c->cancelBuffer(buffer, -1);
}
-int SurfaceTextureClient::hook_lockBuffer(ANativeWindow* window,
+int SurfaceTextureClient::hook_lockBuffer_DEPRECATED(ANativeWindow* window,
ANativeWindowBuffer* buffer) {
SurfaceTextureClient* c = getSelf(window);
- return c->lockBuffer(buffer);
+ return c->lockBuffer_DEPRECATED(buffer);
}
-int SurfaceTextureClient::hook_queueBuffer(ANativeWindow* window,
+int SurfaceTextureClient::hook_queueBuffer_DEPRECATED(ANativeWindow* window,
ANativeWindowBuffer* buffer) {
SurfaceTextureClient* c = getSelf(window);
- return c->queueBuffer(buffer);
+ return c->queueBuffer(buffer, -1);
}
int SurfaceTextureClient::hook_query(const ANativeWindow* window,
@@ -157,14 +190,16 @@ int SurfaceTextureClient::setSwapInterval(int interval) {
return res;
}
-int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer) {
+int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer,
+ int* fenceFd) {
ATRACE_CALL();
ALOGV("SurfaceTextureClient::dequeueBuffer");
Mutex::Autolock lock(mMutex);
int buf = -1;
int reqW = mReqWidth ? mReqWidth : mUserWidth;
int reqH = mReqHeight ? mReqHeight : mUserHeight;
- status_t result = mSurfaceTexture->dequeueBuffer(&buf, reqW, reqH,
+ sp<Fence> fence;
+ status_t result = mSurfaceTexture->dequeueBuffer(&buf, fence, reqW, reqH,
mReqFormat, mReqUsage);
if (result < 0) {
ALOGV("dequeueBuffer: ISurfaceTexture::dequeueBuffer(%d, %d, %d, %d)"
@@ -185,11 +220,21 @@ int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer) {
return result;
}
}
+
+ if (fence.get()) {
+ status_t err = fence->wait(Fence::TIMEOUT_NEVER);
+ if (err != OK) {
+ ALOGE("dequeueBuffer: error waiting for fence: %d", err);
+ }
+ fence.clear();
+ }
+
*buffer = gbuf.get();
+ *fenceFd = -1;
return OK;
}
-int SurfaceTextureClient::cancelBuffer(android_native_buffer_t* buffer) {
+int SurfaceTextureClient::cancelBuffer(android_native_buffer_t* buffer, int fenceFd) {
ATRACE_CALL();
ALOGV("SurfaceTextureClient::cancelBuffer");
Mutex::Autolock lock(mMutex);
@@ -197,6 +242,12 @@ int SurfaceTextureClient::cancelBuffer(android_native_buffer_t* buffer) {
if (i < 0) {
return i;
}
+ sp<Fence> fence(new Fence(fenceFd));
+ status_t err = fence->wait(Fence::TIMEOUT_NEVER);
+ if (err != OK) {
+ ALOGE("queueBuffer: Fence::wait returned an error: %d", err);
+ return err;
+ }
mSurfaceTexture->cancelBuffer(i);
return OK;
}
@@ -214,13 +265,13 @@ int SurfaceTextureClient::getSlotFromBufferLocked(
return BAD_VALUE;
}
-int SurfaceTextureClient::lockBuffer(android_native_buffer_t* buffer) {
+int SurfaceTextureClient::lockBuffer_DEPRECATED(android_native_buffer_t* buffer) {
ALOGV("SurfaceTextureClient::lockBuffer");
Mutex::Autolock lock(mMutex);
return OK;
}
-int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer) {
+int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {
ATRACE_CALL();
ALOGV("SurfaceTextureClient::queueBuffer");
Mutex::Autolock lock(mMutex);
@@ -237,6 +288,13 @@ int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer) {
return i;
}
+ sp<Fence> fence(new Fence(fenceFd));
+ status_t err = fence->wait(Fence::TIMEOUT_NEVER);
+ if (err != OK) {
+ ALOGE("queueBuffer: Fence::wait returned an error: %d", err);
+ return err;
+ }
+
// Make sure the crop rectangle is entirely inside the buffer.
Rect crop;
mCrop.intersect(Rect(buffer->width, buffer->height), &crop);
@@ -244,7 +302,7 @@ int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer) {
ISurfaceTexture::QueueBufferOutput output;
ISurfaceTexture::QueueBufferInput input(timestamp, crop, mScalingMode,
mTransform);
- status_t err = mSurfaceTexture->queueBuffer(i, input, &output);
+ err = mSurfaceTexture->queueBuffer(i, input, &output);
if (err != OK) {
ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err);
}
@@ -692,78 +750,83 @@ status_t SurfaceTextureClient::lock(
}
ANativeWindowBuffer* out;
- status_t err = dequeueBuffer(&out);
+ int fenceFd = -1;
+ status_t err = dequeueBuffer(&out, &fenceFd);
ALOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
if (err == NO_ERROR) {
sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
- err = lockBuffer(backBuffer.get());
- ALOGE_IF(err, "lockBuffer (handle=%p) failed (%s)",
- backBuffer->handle, strerror(-err));
- if (err == NO_ERROR) {
- const Rect bounds(backBuffer->width, backBuffer->height);
-
- Region newDirtyRegion;
- if (inOutDirtyBounds) {
- newDirtyRegion.set(static_cast<Rect const&>(*inOutDirtyBounds));
- newDirtyRegion.andSelf(bounds);
- } else {
- newDirtyRegion.set(bounds);
- }
+ sp<Fence> fence(new Fence(fenceFd));
- // figure out if we can copy the frontbuffer back
- const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
- const bool canCopyBack = (frontBuffer != 0 &&
- backBuffer->width == frontBuffer->width &&
- backBuffer->height == frontBuffer->height &&
- backBuffer->format == frontBuffer->format);
-
- if (canCopyBack) {
- // copy the area that is invalid and not repainted this round
- const Region copyback(mDirtyRegion.subtract(newDirtyRegion));
- if (!copyback.isEmpty())
- copyBlt(backBuffer, frontBuffer, copyback);
- } else {
- // if we can't copy-back anything, modify the user's dirty
- // region to make sure they redraw the whole buffer
- newDirtyRegion.set(bounds);
- mDirtyRegion.clear();
- Mutex::Autolock lock(mMutex);
- for (size_t i=0 ; i<NUM_BUFFER_SLOTS ; i++) {
- mSlots[i].dirtyRegion.clear();
- }
- }
+ err = fence->wait(Fence::TIMEOUT_NEVER);
+ if (err != OK) {
+ ALOGE("Fence::wait failed (%s)", strerror(-err));
+ cancelBuffer(out, fenceFd);
+ return err;
+ }
+ const Rect bounds(backBuffer->width, backBuffer->height);
- { // scope for the lock
- Mutex::Autolock lock(mMutex);
- int backBufferSlot(getSlotFromBufferLocked(backBuffer.get()));
- if (backBufferSlot >= 0) {
- Region& dirtyRegion(mSlots[backBufferSlot].dirtyRegion);
- mDirtyRegion.subtract(dirtyRegion);
- dirtyRegion = newDirtyRegion;
- }
- }
+ Region newDirtyRegion;
+ if (inOutDirtyBounds) {
+ newDirtyRegion.set(static_cast<Rect const&>(*inOutDirtyBounds));
+ newDirtyRegion.andSelf(bounds);
+ } else {
+ newDirtyRegion.set(bounds);
+ }
- mDirtyRegion.orSelf(newDirtyRegion);
- if (inOutDirtyBounds) {
- *inOutDirtyBounds = newDirtyRegion.getBounds();
+ // figure out if we can copy the frontbuffer back
+ const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
+ const bool canCopyBack = (frontBuffer != 0 &&
+ backBuffer->width == frontBuffer->width &&
+ backBuffer->height == frontBuffer->height &&
+ backBuffer->format == frontBuffer->format);
+
+ if (canCopyBack) {
+ // copy the area that is invalid and not repainted this round
+ const Region copyback(mDirtyRegion.subtract(newDirtyRegion));
+ if (!copyback.isEmpty())
+ copyBlt(backBuffer, frontBuffer, copyback);
+ } else {
+ // if we can't copy-back anything, modify the user's dirty
+ // region to make sure they redraw the whole buffer
+ newDirtyRegion.set(bounds);
+ mDirtyRegion.clear();
+ Mutex::Autolock lock(mMutex);
+ for (size_t i=0 ; i<NUM_BUFFER_SLOTS ; i++) {
+ mSlots[i].dirtyRegion.clear();
}
+ }
- void* vaddr;
- status_t res = backBuffer->lock(
- GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
- newDirtyRegion.bounds(), &vaddr);
- ALOGW_IF(res, "failed locking buffer (handle = %p)",
- backBuffer->handle);
+ { // scope for the lock
+ Mutex::Autolock lock(mMutex);
+ int backBufferSlot(getSlotFromBufferLocked(backBuffer.get()));
+ if (backBufferSlot >= 0) {
+ Region& dirtyRegion(mSlots[backBufferSlot].dirtyRegion);
+ mDirtyRegion.subtract(dirtyRegion);
+ dirtyRegion = newDirtyRegion;
+ }
+ }
- mLockedBuffer = backBuffer;
- outBuffer->width = backBuffer->width;
- outBuffer->height = backBuffer->height;
- outBuffer->stride = backBuffer->stride;
- outBuffer->format = backBuffer->format;
- outBuffer->bits = vaddr;
+ mDirtyRegion.orSelf(newDirtyRegion);
+ if (inOutDirtyBounds) {
+ *inOutDirtyBounds = newDirtyRegion.getBounds();
}
+
+ void* vaddr;
+ status_t res = backBuffer->lock(
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ newDirtyRegion.bounds(), &vaddr);
+
+ ALOGW_IF(res, "failed locking buffer (handle = %p)",
+ backBuffer->handle);
+
+ mLockedBuffer = backBuffer;
+ outBuffer->width = backBuffer->width;
+ outBuffer->height = backBuffer->height;
+ outBuffer->stride = backBuffer->stride;
+ outBuffer->format = backBuffer->format;
+ outBuffer->bits = vaddr;
}
return err;
}
@@ -778,7 +841,7 @@ status_t SurfaceTextureClient::unlockAndPost()
status_t err = mLockedBuffer->unlock();
ALOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
- err = queueBuffer(mLockedBuffer.get());
+ err = queueBuffer(mLockedBuffer.get(), -1);
ALOGE_IF(err, "queueBuffer (handle=%p) failed (%s)",
mLockedBuffer->handle, strerror(-err));
diff --git a/libs/gui/tests/Android.mk b/libs/gui/tests/Android.mk
index 741534b..e8863d3 100644
--- a/libs/gui/tests/Android.mk
+++ b/libs/gui/tests/Android.mk
@@ -2,14 +2,15 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_MODULE := SurfaceTexture_test
+LOCAL_MODULE := libgui_test
LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := \
- Surface_test.cpp \
+ CpuConsumer_test.cpp \
SurfaceTextureClient_test.cpp \
SurfaceTexture_test.cpp \
+ Surface_test.cpp \
LOCAL_SHARED_LIBRARIES := \
libEGL \
@@ -18,6 +19,7 @@ LOCAL_SHARED_LIBRARIES := \
libcutils \
libgui \
libstlport \
+ libsync \
libui \
libutils \
diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp
new file mode 100644
index 0000000..371fb8b
--- /dev/null
+++ b/libs/gui/tests/CpuConsumer_test.cpp
@@ -0,0 +1,503 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "CpuConsumer_test"
+//#define LOG_NDEBUG 0
+//#define LOG_NNDEBUG 0
+
+#ifdef LOG_NNDEBUG
+#define ALOGVV(...) ALOGV(__VA_ARGS__)
+#else
+#define ALOGVV(...) ((void)0)
+#endif
+
+#include <gtest/gtest.h>
+#include <gui/CpuConsumer.h>
+#include <gui/SurfaceTextureClient.h>
+#include <ui/GraphicBuffer.h>
+#include <utils/String8.h>
+#include <utils/Thread.h>
+#include <utils/Mutex.h>
+#include <utils/Condition.h>
+
+#include <ui/FramebufferNativeWindow.h>
+
+namespace android {
+
+struct CpuConsumerTestParams {
+ uint32_t width;
+ uint32_t height;
+ int maxLockedBuffers;
+ PixelFormat format;
+};
+
+::std::ostream& operator<<(::std::ostream& os, const CpuConsumerTestParams& p) {
+ return os << "[ (" << p.width << ", " << p.height << "), B:"
+ << p.maxLockedBuffers << ", F:0x"
+ << ::std::hex << p.format << "]";
+}
+
+class CpuConsumerTest : public ::testing::TestWithParam<CpuConsumerTestParams> {
+protected:
+
+ virtual void SetUp() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ CpuConsumerTestParams params = GetParam();
+ ALOGV("** Starting test %s (%d x %d, %d, 0x%x)",
+ test_info->name(),
+ params.width, params.height,
+ params.maxLockedBuffers, params.format);
+ mCC = new CpuConsumer(params.maxLockedBuffers);
+ String8 name("CpuConsumer_Under_Test");
+ mCC->setName(name);
+ mSTC = new SurfaceTextureClient(mCC->getProducerInterface());
+ mANW = mSTC;
+ }
+
+ virtual void TearDown() {
+ mANW.clear();
+ mSTC.clear();
+ mCC.clear();
+ }
+
+ class FrameWaiter : public CpuConsumer::FrameAvailableListener {
+ public:
+ FrameWaiter():
+ mPendingFrames(0) {
+ }
+
+ void waitForFrame() {
+ Mutex::Autolock lock(mMutex);
+ while (mPendingFrames == 0) {
+ mCondition.wait(mMutex);
+ }
+ mPendingFrames--;
+ }
+
+ virtual void onFrameAvailable() {
+ Mutex::Autolock lock(mMutex);
+ mPendingFrames++;
+ mCondition.signal();
+ }
+
+ int mPendingFrames;
+ Mutex mMutex;
+ Condition mCondition;
+ };
+
+ // Note that SurfaceTexture will lose the notifications
+ // onBuffersReleased and onFrameAvailable as there is currently
+ // no way to forward the events. This DisconnectWaiter will not let the
+ // disconnect finish until finishDisconnect() is called. It will
+ // also block until a disconnect is called
+ class DisconnectWaiter : public BufferQueue::ConsumerListener {
+ public:
+ DisconnectWaiter () :
+ mWaitForDisconnect(false),
+ mPendingFrames(0) {
+ }
+
+ void waitForFrame() {
+ Mutex::Autolock lock(mMutex);
+ while (mPendingFrames == 0) {
+ mFrameCondition.wait(mMutex);
+ }
+ mPendingFrames--;
+ }
+
+ virtual void onFrameAvailable() {
+ Mutex::Autolock lock(mMutex);
+ mPendingFrames++;
+ mFrameCondition.signal();
+ }
+
+ virtual void onBuffersReleased() {
+ Mutex::Autolock lock(mMutex);
+ while (!mWaitForDisconnect) {
+ mDisconnectCondition.wait(mMutex);
+ }
+ }
+
+ void finishDisconnect() {
+ Mutex::Autolock lock(mMutex);
+ mWaitForDisconnect = true;
+ mDisconnectCondition.signal();
+ }
+
+ private:
+ Mutex mMutex;
+
+ bool mWaitForDisconnect;
+ Condition mDisconnectCondition;
+
+ int mPendingFrames;
+ Condition mFrameCondition;
+ };
+
+ sp<CpuConsumer> mCC;
+ sp<SurfaceTextureClient> mSTC;
+ sp<ANativeWindow> mANW;
+};
+
+#define ASSERT_NO_ERROR(err, msg) \
+ ASSERT_EQ(NO_ERROR, err) << msg << strerror(-err)
+
+void checkPixel(const CpuConsumer::LockedBuffer &buf,
+ uint32_t x, uint32_t y, uint32_t r, uint32_t g, uint32_t b) {
+ // Ignores components that don't exist for given pixel
+ switch(buf.format) {
+ case HAL_PIXEL_FORMAT_RAW_SENSOR: {
+ String8 msg;
+ uint16_t *bPtr = (uint16_t*)buf.data;
+ bPtr += y * buf.stride + x;
+ // GRBG Bayer mosaic; only check the matching channel
+ switch( ((y & 1) << 1) | (x & 1) ) {
+ case 0: // G
+ case 3: // G
+ EXPECT_EQ(g, *bPtr);
+ break;
+ case 1: // R
+ EXPECT_EQ(r, *bPtr);
+ break;
+ case 2: // B
+ EXPECT_EQ(b, *bPtr);
+ break;
+ }
+ break;
+ }
+ default: {
+ ADD_FAILURE() << "Unknown format for check:" << buf.format;
+ break;
+ }
+ }
+}
+
+// Fill a YV12 buffer with a multi-colored checkerboard pattern
+void fillYV12Buffer(uint8_t* buf, int w, int h, int stride);
+
+// Fill a RAW sensor buffer with a multi-colored checkerboard pattern.
+// Assumes GRBG mosaic ordering. Result should be a grid in a 2x2 pattern
+// of [ R, B; G, W]
+void fillBayerRawBuffer(uint8_t* buf, int w, int h, int stride) {
+ ALOGVV("fillBayerRawBuffer: %p with %d x %d, stride %d", buf, w, h ,stride);
+ // Blocks need to be even-width/height, aim for 8-wide otherwise
+ const int blockWidth = (w > 16 ? w / 8 : 2) & ~0x1;
+ const int blockHeight = (h > 16 ? h / 8 : 2) & ~0x1;
+ for (int y = 0; y < h; y+=2) {
+ uint16_t *bPtr1 = ((uint16_t*)buf) + stride*y;
+ uint16_t *bPtr2 = bPtr1 + stride;
+ for (int x = 0; x < w; x+=2) {
+ int blockX = (x / blockWidth ) & 1;
+ int blockY = (y / blockHeight) & 1;
+ unsigned short r = (blockX == blockY) ? 1000 : 200;
+ unsigned short g = blockY ? 1000: 200;
+ unsigned short b = blockX ? 1000: 200;
+ // GR row
+ *bPtr1++ = g;
+ *bPtr1++ = r;
+ // BG row
+ *bPtr2++ = b;
+ *bPtr2++ = g;
+ }
+ }
+
+}
+
+void checkBayerRawBuffer(const CpuConsumer::LockedBuffer &buf) {
+ uint32_t w = buf.width;
+ uint32_t h = buf.height;
+ const int blockWidth = (w > 16 ? w / 8 : 2) & ~0x1;
+ const int blockHeight = (h > 16 ? h / 8 : 2) & ~0x1;
+ const int blockRows = h / blockHeight;
+ const int blockCols = w / blockWidth;
+
+ // Top-left square is red
+ checkPixel(buf, 0, 0, 1000, 200, 200);
+ checkPixel(buf, 1, 0, 1000, 200, 200);
+ checkPixel(buf, 0, 1, 1000, 200, 200);
+ checkPixel(buf, 1, 1, 1000, 200, 200);
+
+ // One-right square is blue
+ checkPixel(buf, blockWidth, 0, 200, 200, 1000);
+ checkPixel(buf, blockWidth + 1, 0, 200, 200, 1000);
+ checkPixel(buf, blockWidth, 1, 200, 200, 1000);
+ checkPixel(buf, blockWidth + 1, 1, 200, 200, 1000);
+
+ // One-down square is green
+ checkPixel(buf, 0, blockHeight, 200, 1000, 200);
+ checkPixel(buf, 1, blockHeight, 200, 1000, 200);
+ checkPixel(buf, 0, blockHeight + 1, 200, 1000, 200);
+ checkPixel(buf, 1, blockHeight + 1, 200, 1000, 200);
+
+ // One-diag square is white
+ checkPixel(buf, blockWidth, blockHeight, 1000, 1000, 1000);
+ checkPixel(buf, blockWidth + 1, blockHeight, 1000, 1000, 1000);
+ checkPixel(buf, blockWidth, blockHeight + 1, 1000, 1000, 1000);
+ checkPixel(buf, blockWidth + 1, blockHeight + 1, 1000, 1000, 1000);
+
+ // Test bottom-right pixel
+ const int maxBlockX = ((w-1) / blockWidth) & 0x1;
+ const int maxBlockY = ((w-1) / blockHeight) & 0x1;
+ unsigned short maxR = (maxBlockX == maxBlockY) ? 1000 : 200;
+ unsigned short maxG = maxBlockY ? 1000: 200;
+ unsigned short maxB = maxBlockX ? 1000: 200;
+ checkPixel(buf, w-1, h-1, maxR, maxG, maxB);
+}
+
+void fillYV12BufferRect(uint8_t* buf, int w, int h, int stride,
+ const android_native_rect_t& rect);
+
+void fillRGBA8Buffer(uint8_t* buf, int w, int h, int stride);
+
+void fillRGBA8BufferSolid(uint8_t* buf, int w, int h, int stride, uint8_t r,
+ uint8_t g, uint8_t b, uint8_t a);
+
+// Configures the ANativeWindow producer-side interface based on test parameters
+void configureANW(const sp<ANativeWindow>& anw,
+ const CpuConsumerTestParams& params,
+ int maxBufferSlack) {
+ status_t err;
+ err = native_window_set_buffers_geometry(anw.get(),
+ params.width, params.height, params.format);
+ ASSERT_NO_ERROR(err, "set_buffers_geometry error: ");
+
+ err = native_window_set_usage(anw.get(),
+ GRALLOC_USAGE_SW_WRITE_OFTEN);
+ ASSERT_NO_ERROR(err, "set_usage error: ");
+
+ int minUndequeuedBuffers;
+ err = anw.get()->query(anw.get(),
+ NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+ &minUndequeuedBuffers);
+ ASSERT_NO_ERROR(err, "query error: ");
+
+ ALOGVV("Setting buffer count to %d",
+ maxBufferSlack + 1 + minUndequeuedBuffers);
+ err = native_window_set_buffer_count(anw.get(),
+ maxBufferSlack + 1 + minUndequeuedBuffers);
+ ASSERT_NO_ERROR(err, "set_buffer_count error: ");
+
+}
+
+// Produce one frame of image data; assumes format and resolution configuration
+// is already done.
+void produceOneFrame(const sp<ANativeWindow>& anw,
+ const CpuConsumerTestParams& params,
+ int64_t timestamp, uint32_t *stride) {
+ status_t err;
+ ANativeWindowBuffer* anb;
+ ALOGVV("Dequeue buffer from %p", anw.get());
+ err = native_window_dequeue_buffer_and_wait(anw.get(), &anb);
+ ASSERT_NO_ERROR(err, "dequeueBuffer error: ");
+
+ ASSERT_TRUE(anb != NULL);
+
+ sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+
+ *stride = buf->getStride();
+ uint8_t* img = NULL;
+
+ ALOGVV("Lock buffer from %p for write", anw.get());
+ err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
+ ASSERT_NO_ERROR(err, "lock error: ");
+
+ switch (params.format) {
+ case HAL_PIXEL_FORMAT_YV12:
+ fillYV12Buffer(img, params.width, params.height, *stride);
+ break;
+ case HAL_PIXEL_FORMAT_RAW_SENSOR:
+ fillBayerRawBuffer(img, params.width, params.height, buf->getStride());
+ break;
+ default:
+ FAIL() << "Unknown pixel format under test!";
+ break;
+ }
+ ALOGVV("Unlock buffer from %p", anw.get());
+ err = buf->unlock();
+ ASSERT_NO_ERROR(err, "unlock error: ");
+
+ ALOGVV("Set timestamp to %p", anw.get());
+ err = native_window_set_buffers_timestamp(anw.get(), timestamp);
+ ASSERT_NO_ERROR(err, "set_buffers_timestamp error: ");
+
+ ALOGVV("Queue buffer to %p", anw.get());
+ err = anw->queueBuffer(anw.get(), buf->getNativeBuffer(), -1);
+ ASSERT_NO_ERROR(err, "queueBuffer error:");
+};
+
+TEST_P(CpuConsumerTest, FromCpuSingle) {
+ status_t err;
+ CpuConsumerTestParams params = GetParam();
+
+ // Set up
+
+ ASSERT_NO_FATAL_FAILURE(configureANW(mANW, params, 1));
+
+ // Produce
+
+ const int64_t time = 12345678L;
+ uint32_t stride;
+ ASSERT_NO_FATAL_FAILURE(produceOneFrame(mANW, params, time,
+ &stride));
+
+ // Consume
+
+ CpuConsumer::LockedBuffer b;
+ err = mCC->lockNextBuffer(&b);
+ ASSERT_NO_ERROR(err, "getNextBuffer error: ");
+
+ ASSERT_TRUE(b.data != NULL);
+ EXPECT_EQ(params.width, b.width);
+ EXPECT_EQ(params.height, b.height);
+ EXPECT_EQ(params.format, b.format);
+ EXPECT_EQ(stride, b.stride);
+ EXPECT_EQ(time, b.timestamp);
+
+ checkBayerRawBuffer(b);
+ mCC->unlockBuffer(b);
+}
+
+TEST_P(CpuConsumerTest, FromCpuManyInQueue) {
+ status_t err;
+ CpuConsumerTestParams params = GetParam();
+
+ const int numInQueue = 5;
+ // Set up
+
+ ASSERT_NO_FATAL_FAILURE(configureANW(mANW, params, numInQueue));
+
+ // Produce
+
+ const int64_t time[numInQueue] = { 1L, 2L, 3L, 4L, 5L};
+ uint32_t stride[numInQueue];
+
+ for (int i = 0; i < numInQueue; i++) {
+ ALOGV("Producing frame %d", i);
+ ASSERT_NO_FATAL_FAILURE(produceOneFrame(mANW, params, time[i],
+ &stride[i]));
+ }
+
+ // Consume
+
+ for (int i = 0; i < numInQueue; i++) {
+ ALOGV("Consuming frame %d", i);
+ CpuConsumer::LockedBuffer b;
+ err = mCC->lockNextBuffer(&b);
+ ASSERT_NO_ERROR(err, "getNextBuffer error: ");
+
+ ASSERT_TRUE(b.data != NULL);
+ EXPECT_EQ(params.width, b.width);
+ EXPECT_EQ(params.height, b.height);
+ EXPECT_EQ(params.format, b.format);
+ EXPECT_EQ(stride[i], b.stride);
+ EXPECT_EQ(time[i], b.timestamp);
+
+ checkBayerRawBuffer(b);
+
+ mCC->unlockBuffer(b);
+ }
+}
+
+TEST_P(CpuConsumerTest, FromCpuLockMax) {
+ status_t err;
+ CpuConsumerTestParams params = GetParam();
+
+ // Set up
+
+ ASSERT_NO_FATAL_FAILURE(configureANW(mANW, params, params.maxLockedBuffers + 1));
+
+ // Produce
+
+ const int64_t time = 1234L;
+ uint32_t stride;
+
+ for (int i = 0; i < params.maxLockedBuffers + 1; i++) {
+ ALOGV("Producing frame %d", i);
+ ASSERT_NO_FATAL_FAILURE(produceOneFrame(mANW, params, time,
+ &stride));
+ }
+
+ // Consume
+
+ CpuConsumer::LockedBuffer *b = new CpuConsumer::LockedBuffer[params.maxLockedBuffers];
+ for (int i = 0; i < params.maxLockedBuffers; i++) {
+ ALOGV("Locking frame %d", i);
+ err = mCC->lockNextBuffer(&b[i]);
+ ASSERT_NO_ERROR(err, "getNextBuffer error: ");
+
+ ASSERT_TRUE(b[i].data != NULL);
+ EXPECT_EQ(params.width, b[i].width);
+ EXPECT_EQ(params.height, b[i].height);
+ EXPECT_EQ(params.format, b[i].format);
+ EXPECT_EQ(stride, b[i].stride);
+ EXPECT_EQ(time, b[i].timestamp);
+
+ checkBayerRawBuffer(b[i]);
+ }
+
+ ALOGV("Locking frame %d (too many)", params.maxLockedBuffers);
+ CpuConsumer::LockedBuffer bTooMuch;
+ err = mCC->lockNextBuffer(&bTooMuch);
+ ASSERT_TRUE(err == INVALID_OPERATION) << "Allowing too many locks";
+
+ ALOGV("Unlocking frame 0");
+ err = mCC->unlockBuffer(b[0]);
+ ASSERT_NO_ERROR(err, "Could not unlock buffer 0: ");
+
+ ALOGV("Locking frame %d (should work now)", params.maxLockedBuffers);
+ err = mCC->lockNextBuffer(&bTooMuch);
+ ASSERT_NO_ERROR(err, "Did not allow new lock after unlock");
+
+ ASSERT_TRUE(bTooMuch.data != NULL);
+ EXPECT_EQ(params.width, bTooMuch.width);
+ EXPECT_EQ(params.height, bTooMuch.height);
+ EXPECT_EQ(params.format, bTooMuch.format);
+ EXPECT_EQ(stride, bTooMuch.stride);
+ EXPECT_EQ(time, bTooMuch.timestamp);
+
+ checkBayerRawBuffer(bTooMuch);
+
+ ALOGV("Unlocking extra buffer");
+ err = mCC->unlockBuffer(bTooMuch);
+ ASSERT_NO_ERROR(err, "Could not unlock extra buffer: ");
+
+ ALOGV("Locking frame %d (no more available)", params.maxLockedBuffers + 1);
+ err = mCC->lockNextBuffer(&b[0]);
+ ASSERT_EQ(BAD_VALUE, err) << "Not out of buffers somehow";
+
+ for (int i = 1; i < params.maxLockedBuffers; i++) {
+ mCC->unlockBuffer(b[i]);
+ }
+
+ delete[] b;
+
+}
+
+CpuConsumerTestParams rawTestSets[] = {
+ { 512, 512, 1, HAL_PIXEL_FORMAT_RAW_SENSOR},
+ { 512, 512, 3, HAL_PIXEL_FORMAT_RAW_SENSOR},
+ { 2608, 1960, 1, HAL_PIXEL_FORMAT_RAW_SENSOR},
+ { 2608, 1960, 3, HAL_PIXEL_FORMAT_RAW_SENSOR},
+ { 100, 100, 1, HAL_PIXEL_FORMAT_RAW_SENSOR},
+ { 100, 100, 3, HAL_PIXEL_FORMAT_RAW_SENSOR}
+};
+
+INSTANTIATE_TEST_CASE_P(RawTests,
+ CpuConsumerTest,
+ ::testing::ValuesIn(rawTestSets));
+
+} // namespace android
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index 7d8dd33..59b9efd 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -180,129 +180,129 @@ TEST_F(SurfaceTextureClientTest, BufferGeometryInvalidSizesFail) {
TEST_F(SurfaceTextureClientTest, DefaultGeometryValues) {
ANativeWindowBuffer* buf;
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf));
EXPECT_EQ(1, buf->width);
EXPECT_EQ(1, buf->height);
EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format);
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1));
}
TEST_F(SurfaceTextureClientTest, BufferGeometryCanBeSet) {
ANativeWindowBuffer* buf;
EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 16, 8, PIXEL_FORMAT_RGB_565));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf));
EXPECT_EQ(16, buf->width);
EXPECT_EQ(8, buf->height);
EXPECT_EQ(PIXEL_FORMAT_RGB_565, buf->format);
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1));
}
TEST_F(SurfaceTextureClientTest, BufferGeometryDefaultSizeSetFormat) {
ANativeWindowBuffer* buf;
EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 0, 0, PIXEL_FORMAT_RGB_565));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf));
EXPECT_EQ(1, buf->width);
EXPECT_EQ(1, buf->height);
EXPECT_EQ(PIXEL_FORMAT_RGB_565, buf->format);
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1));
}
TEST_F(SurfaceTextureClientTest, BufferGeometrySetSizeDefaultFormat) {
ANativeWindowBuffer* buf;
EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 16, 8, 0));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf));
EXPECT_EQ(16, buf->width);
EXPECT_EQ(8, buf->height);
EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format);
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1));
}
TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeUnset) {
ANativeWindowBuffer* buf;
EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 16, 8, 0));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf));
EXPECT_EQ(16, buf->width);
EXPECT_EQ(8, buf->height);
EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format);
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1));
EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 0, 0, 0));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf));
EXPECT_EQ(1, buf->width);
EXPECT_EQ(1, buf->height);
EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format);
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1));
}
TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeChangedWithoutFormat) {
ANativeWindowBuffer* buf;
EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 0, 0, PIXEL_FORMAT_RGB_565));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf));
EXPECT_EQ(1, buf->width);
EXPECT_EQ(1, buf->height);
EXPECT_EQ(PIXEL_FORMAT_RGB_565, buf->format);
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1));
EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 16, 8, 0));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf));
EXPECT_EQ(16, buf->width);
EXPECT_EQ(8, buf->height);
EXPECT_EQ(PIXEL_FORMAT_RGB_565, buf->format);
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1));
}
TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSize) {
sp<SurfaceTexture> st(mST);
ANativeWindowBuffer* buf;
EXPECT_EQ(OK, st->setDefaultBufferSize(16, 8));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf));
EXPECT_EQ(16, buf->width);
EXPECT_EQ(8, buf->height);
EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format);
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1));
}
TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeAfterDequeue) {
ANativeWindowBuffer* buf[2];
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
EXPECT_NE(buf[0], buf[1]);
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0]));
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1]));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0], -1));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1], -1));
EXPECT_EQ(OK, mST->setDefaultBufferSize(16, 8));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
EXPECT_NE(buf[0], buf[1]);
EXPECT_EQ(16, buf[0]->width);
EXPECT_EQ(16, buf[1]->width);
EXPECT_EQ(8, buf[0]->height);
EXPECT_EQ(8, buf[1]->height);
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0]));
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1]));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0], -1));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1], -1));
}
TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeVsGeometry) {
ANativeWindowBuffer* buf[2];
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
EXPECT_EQ(OK, mST->setDefaultBufferSize(16, 8));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
EXPECT_NE(buf[0], buf[1]);
EXPECT_EQ(16, buf[0]->width);
EXPECT_EQ(16, buf[1]->width);
EXPECT_EQ(8, buf[0]->height);
EXPECT_EQ(8, buf[1]->height);
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0]));
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1]));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0], -1));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1], -1));
EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 12, 24, 0));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
EXPECT_NE(buf[0], buf[1]);
EXPECT_EQ(12, buf[0]->width);
EXPECT_EQ(12, buf[1]->width);
EXPECT_EQ(24, buf[0]->height);
EXPECT_EQ(24, buf[1]->height);
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0]));
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1]));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0], -1));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1], -1));
}
TEST_F(SurfaceTextureClientTest, SurfaceTextureTooManyUpdateTexImage) {
@@ -310,18 +310,18 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureTooManyUpdateTexImage) {
ASSERT_EQ(OK, mST->setSynchronousMode(false));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1));
EXPECT_EQ(OK, mST->updateTexImage());
EXPECT_EQ(OK, mST->updateTexImage());
ASSERT_EQ(OK, mST->setSynchronousMode(true));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0]));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1], -1));
EXPECT_EQ(OK, mST->updateTexImage());
EXPECT_EQ(OK, mST->updateTexImage());
@@ -332,15 +332,15 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeSlowRetire) {
android_native_buffer_t* buf[3];
ASSERT_EQ(OK, mST->setSynchronousMode(true));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[2]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[2]));
EXPECT_NE(buf[0], buf[1]);
EXPECT_NE(buf[1], buf[2]);
EXPECT_NE(buf[2], buf[0]);
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0]));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1]));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1], -1));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2], -1));
EXPECT_EQ(OK, mST->updateTexImage());
EXPECT_EQ(mST->getCurrentBuffer().get(), buf[0]);
EXPECT_EQ(OK, mST->updateTexImage());
@@ -353,19 +353,19 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeFastRetire) {
android_native_buffer_t* buf[3];
ASSERT_EQ(OK, mST->setSynchronousMode(true));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[2]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[2]));
EXPECT_NE(buf[0], buf[1]);
EXPECT_NE(buf[1], buf[2]);
EXPECT_NE(buf[2], buf[0]);
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1));
EXPECT_EQ(OK, mST->updateTexImage());
EXPECT_EQ(mST->getCurrentBuffer().get(), buf[0]);
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1], -1));
EXPECT_EQ(OK, mST->updateTexImage());
EXPECT_EQ(mST->getCurrentBuffer().get(), buf[1]);
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2], -1));
EXPECT_EQ(OK, mST->updateTexImage());
EXPECT_EQ(mST->getCurrentBuffer().get(), buf[2]);
}
@@ -375,20 +375,20 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeDQQR) {
ASSERT_EQ(OK, mST->setSynchronousMode(true));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1));
EXPECT_EQ(OK, mST->updateTexImage());
EXPECT_EQ(mST->getCurrentBuffer().get(), buf[0]);
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
EXPECT_NE(buf[0], buf[1]);
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1], -1));
EXPECT_EQ(OK, mST->updateTexImage());
EXPECT_EQ(mST->getCurrentBuffer().get(), buf[1]);
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[2]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[2]));
EXPECT_NE(buf[1], buf[2]);
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2], -1));
EXPECT_EQ(OK, mST->updateTexImage());
EXPECT_EQ(mST->getCurrentBuffer().get(), buf[2]);
}
@@ -400,16 +400,16 @@ TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeDequeueCurrent)
android_native_buffer_t* firstBuf;
ASSERT_EQ(OK, mST->setSynchronousMode(true));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &firstBuf));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), firstBuf));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &firstBuf));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), firstBuf, -1));
EXPECT_EQ(OK, mST->updateTexImage());
EXPECT_EQ(mST->getCurrentBuffer().get(), firstBuf);
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0]));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1]));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[2]));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1], -1));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[2]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2], -1));
EXPECT_NE(buf[0], buf[1]);
EXPECT_NE(buf[1], buf[2]);
EXPECT_NE(buf[2], buf[0]);
@@ -422,24 +422,24 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeMinUndequeued) {
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
// We should be able to dequeue all the buffers before we've queued mANWy.
- EXPECT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
- EXPECT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
- EXPECT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[2]));
+ EXPECT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
+ EXPECT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
+ EXPECT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[2]));
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[2]));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1]));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[2], -1));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1], -1));
EXPECT_EQ(OK, mST->updateTexImage());
EXPECT_EQ(mST->getCurrentBuffer().get(), buf[1]);
- EXPECT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[2]));
+ EXPECT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[2]));
// Once we've queued a buffer, however we should not be able to dequeue more
// than (buffer-count - MIN_UNDEQUEUED_BUFFERS), which is 2 in this case.
- EXPECT_EQ(-EBUSY, mANW->dequeueBuffer(mANW.get(), &buf[1]));
+ EXPECT_EQ(-EBUSY, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0]));
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[2]));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0], -1));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[2], -1));
}
TEST_F(SurfaceTextureClientTest, SetCropCropsCrop) {
@@ -449,8 +449,8 @@ TEST_F(SurfaceTextureClientTest, SetCropCropsCrop) {
ASSERT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 4, 4));
android_native_buffer_t* buf;
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf, -1));
ASSERT_EQ(OK, mST->updateTexImage());
Rect crop = mST->getCurrentCrop();
@@ -500,20 +500,20 @@ TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeWaitRetire) {
ASSERT_EQ(OK, mST->setSynchronousMode(true));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
// dequeue/queue/update so we have a current buffer
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1));
mST->updateTexImage();
MyThread* thread = new MyThread(mST);
sp<Thread> threadBase(thread);
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1));
thread->run();
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1]));
- //ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[2]));
- //ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1], -1));
+ //ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[2]));
+ //ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2], -1));
thread->bufferDequeued();
thread->requestExitAndWait();
}
@@ -522,8 +522,8 @@ TEST_F(SurfaceTextureClientTest, GetTransformMatrixReturnsVerticalFlip) {
android_native_buffer_t* buf[3];
float mtx[16] = {};
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1));
ASSERT_EQ(OK, mST->updateTexImage());
mST->getTransformMatrix(mtx);
@@ -552,8 +552,8 @@ TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffers)
android_native_buffer_t* buf[3];
float mtx[16] = {};
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1));
ASSERT_EQ(OK, mST->updateTexImage());
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 6)); // frees buffers
mST->getTransformMatrix(mtx);
@@ -590,9 +590,9 @@ TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffersWi
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
ASSERT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 8, 8, 0));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
ASSERT_EQ(OK, native_window_set_crop(mANW.get(), &crop));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1));
ASSERT_EQ(OK, mST->updateTexImage());
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 6)); // frees buffers
mST->getTransformMatrix(mtx);
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index 078c17b..0060cf7 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -672,18 +672,19 @@ void fillRGBA8BufferSolid(uint8_t* buf, int w, int h, int stride, uint8_t r,
// Calls to this function should be wrapped in an ASSERT_NO_FATAL_FAILURE().
void produceOneRGBA8Frame(const sp<ANativeWindow>& anw) {
android_native_buffer_t* anb;
- ASSERT_EQ(NO_ERROR, anw->dequeueBuffer(anw.get(), &anb));
+ ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(anw.get(),
+ &anb));
ASSERT_TRUE(anb != NULL);
sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
- ASSERT_EQ(NO_ERROR, anw->lockBuffer(anw.get(), buf->getNativeBuffer()));
uint8_t* img = NULL;
ASSERT_EQ(NO_ERROR, buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN,
(void**)(&img)));
fillRGBA8Buffer(img, buf->getWidth(), buf->getHeight(), buf->getStride());
ASSERT_EQ(NO_ERROR, buf->unlock());
- ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf->getNativeBuffer()));
+ ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf->getNativeBuffer(),
+ -1));
}
TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferNpot) {
@@ -696,18 +697,19 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferNpot) {
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
ANativeWindowBuffer* anb;
- ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+ ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(),
+ &anb));
ASSERT_TRUE(anb != NULL);
sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
- ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
// Fill the buffer with the a checkerboard pattern
uint8_t* img = NULL;
buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
fillYV12Buffer(img, texWidth, texHeight, buf->getStride());
buf->unlock();
- ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
+ ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(),
+ -1));
mST->updateTexImage();
@@ -741,18 +743,19 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferPow2) {
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
ANativeWindowBuffer* anb;
- ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+ ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(),
+ &anb));
ASSERT_TRUE(anb != NULL);
sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
- ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
// Fill the buffer with the a checkerboard pattern
uint8_t* img = NULL;
buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
fillYV12Buffer(img, texWidth, texHeight, buf->getStride());
buf->unlock();
- ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
+ ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(),
+ -1));
mST->updateTexImage();
@@ -801,19 +804,18 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferWithCrop) {
ASSERT_EQ(NO_ERROR, native_window_set_crop(mANW.get(), &crop));
ANativeWindowBuffer* anb;
- ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+ ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(),
+ &anb));
ASSERT_TRUE(anb != NULL);
sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
- ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(),
- buf->getNativeBuffer()));
uint8_t* img = NULL;
buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
fillYV12BufferRect(img, texWidth, texHeight, buf->getStride(), crop);
buf->unlock();
ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(),
- buf->getNativeBuffer()));
+ buf->getNativeBuffer(), -1));
mST->updateTexImage();
@@ -877,7 +879,8 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BuffersRepeatedly) {
virtual bool threadLoop() {
for (int i = 0; i < numFrames; i++) {
ANativeWindowBuffer* anb;
- if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) {
+ if (native_window_dequeue_buffer_and_wait(mANW.get(),
+ &anb) != NO_ERROR) {
return false;
}
if (anb == NULL) {
@@ -885,10 +888,6 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BuffersRepeatedly) {
}
sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
- if (mANW->lockBuffer(mANW.get(), buf->getNativeBuffer())
- != NO_ERROR) {
- return false;
- }
const int yuvTexOffsetY = 0;
int stride = buf->getStride();
@@ -932,7 +931,7 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BuffersRepeatedly) {
}
buf->unlock();
- if (mANW->queueBuffer(mANW.get(), buf->getNativeBuffer())
+ if (mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(), -1)
!= NO_ERROR) {
return false;
}
@@ -1093,13 +1092,14 @@ TEST_F(SurfaceTextureGLTest, DisconnectStressTest) {
for (int numFrames =0 ; numFrames < 2; numFrames ++) {
- if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) {
+ if (native_window_dequeue_buffer_and_wait(mANW.get(),
+ &anb) != NO_ERROR) {
return false;
}
if (anb == NULL) {
return false;
}
- if (mANW->queueBuffer(mANW.get(), anb)
+ if (mANW->queueBuffer(mANW.get(), anb, -1)
!= NO_ERROR) {
return false;
}
@@ -1147,11 +1147,11 @@ TEST_F(SurfaceTextureGLTest, DisconnectClearsCurrentTexture) {
ANativeWindowBuffer *anb;
- EXPECT_EQ (OK, mANW->dequeueBuffer(mANW.get(), &anb));
- EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb));
+ EXPECT_EQ (OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
+ EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1));
- EXPECT_EQ (OK, mANW->dequeueBuffer(mANW.get(), &anb));
- EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb));
+ EXPECT_EQ (OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
+ EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1));
EXPECT_EQ(OK,mST->updateTexImage());
EXPECT_EQ(OK,mST->updateTexImage());
@@ -1163,8 +1163,8 @@ TEST_F(SurfaceTextureGLTest, DisconnectClearsCurrentTexture) {
ASSERT_EQ(OK, mST->setSynchronousMode(true));
- EXPECT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &anb));
- EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb));
+ EXPECT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
+ EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1));
// Will fail here if mCurrentTexture is not cleared properly
mFW->waitForFrame();
@@ -1193,8 +1193,8 @@ TEST_F(SurfaceTextureGLTest, ScaleToWindowMode) {
android_native_rect_t odd = {23, 78, 123, 477};
ASSERT_EQ(OK, native_window_set_crop(mANW.get(), &odd));
- EXPECT_EQ (OK, mANW->dequeueBuffer(mANW.get(), &anb));
- EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb));
+ EXPECT_EQ (OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
+ EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1));
mFW->waitForFrame();
EXPECT_EQ(OK,mST->updateTexImage());
Rect r = mST->getCurrentCrop();
@@ -1227,8 +1227,8 @@ TEST_F(SurfaceTextureGLTest, CroppedScalingMode) {
// The crop is in the shape of (320, 180) === 16 x 9
android_native_rect_t standard = {10, 20, 330, 200};
ASSERT_EQ(OK, native_window_set_crop(mANW.get(), &standard));
- EXPECT_EQ (OK, mANW->dequeueBuffer(mANW.get(), &anb));
- EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb));
+ EXPECT_EQ (OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
+ EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1));
mFW->waitForFrame();
EXPECT_EQ(OK,mST->updateTexImage());
Rect r = mST->getCurrentCrop();
@@ -1238,8 +1238,8 @@ TEST_F(SurfaceTextureGLTest, CroppedScalingMode) {
// make this wider then desired aspect 239 x 100 (2.39:1)
android_native_rect_t wide = {20, 30, 259, 130};
ASSERT_EQ(OK, native_window_set_crop(mANW.get(), &wide));
- EXPECT_EQ (OK, mANW->dequeueBuffer(mANW.get(), &anb));
- EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb));
+ EXPECT_EQ (OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
+ EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1));
mFW->waitForFrame();
EXPECT_EQ(OK,mST->updateTexImage());
r = mST->getCurrentCrop();
@@ -1250,8 +1250,8 @@ TEST_F(SurfaceTextureGLTest, CroppedScalingMode) {
// This image is taller then desired aspect 400 x 300 (4:3)
android_native_rect_t narrow = {0, 0, 400, 300};
ASSERT_EQ(OK, native_window_set_crop(mANW.get(), &narrow));
- EXPECT_EQ (OK, mANW->dequeueBuffer(mANW.get(), &anb));
- EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb));
+ EXPECT_EQ (OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
+ EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1));
mFW->waitForFrame();
EXPECT_EQ(OK,mST->updateTexImage());
r = mST->getCurrentCrop();
@@ -1278,31 +1278,34 @@ TEST_F(SurfaceTextureGLTest, AbandonUnblocksDequeueBuffer) {
ANativeWindowBuffer* anb;
// Frame 1
- if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) {
+ if (native_window_dequeue_buffer_and_wait(mANW.get(),
+ &anb) != NO_ERROR) {
return false;
}
if (anb == NULL) {
return false;
}
- if (mANW->queueBuffer(mANW.get(), anb)
+ if (mANW->queueBuffer(mANW.get(), anb, -1)
!= NO_ERROR) {
return false;
}
// Frame 2
- if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) {
+ if (native_window_dequeue_buffer_and_wait(mANW.get(),
+ &anb) != NO_ERROR) {
return false;
}
if (anb == NULL) {
return false;
}
- if (mANW->queueBuffer(mANW.get(), anb)
+ if (mANW->queueBuffer(mANW.get(), anb, -1)
!= NO_ERROR) {
return false;
}
// Frame 3 - error expected
- mDequeueError = mANW->dequeueBuffer(mANW.get(), &anb);
+ mDequeueError = native_window_dequeue_buffer_and_wait(mANW.get(),
+ &anb);
return false;
}
@@ -1346,26 +1349,29 @@ TEST_F(SurfaceTextureGLTest, InvalidWidthOrHeightFails) {
// make sure it works with small textures
mST->setDefaultBufferSize(16, texHeight);
- EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+ EXPECT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(),
+ &anb));
EXPECT_EQ(16, anb->width);
EXPECT_EQ(texHeight, anb->height);
- EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb));
+ EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb, -1));
EXPECT_EQ(NO_ERROR, mST->updateTexImage());
// make sure it works with GL_MAX_TEXTURE_SIZE
mST->setDefaultBufferSize(maxTextureSize, texHeight);
- EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+ EXPECT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(),
+ &anb));
EXPECT_EQ(maxTextureSize, anb->width);
EXPECT_EQ(texHeight, anb->height);
- EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb));
+ EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb, -1));
EXPECT_EQ(NO_ERROR, mST->updateTexImage());
// make sure it fails with GL_MAX_TEXTURE_SIZE+1
mST->setDefaultBufferSize(maxTextureSize+1, texHeight);
- EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+ EXPECT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(),
+ &anb));
EXPECT_EQ(maxTextureSize+1, anb->width);
EXPECT_EQ(texHeight, anb->height);
- EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb));
+ EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb, -1));
ASSERT_NE(NO_ERROR, mST->updateTexImage());
}
@@ -2134,11 +2140,11 @@ TEST_F(SurfaceTextureFBOTest, BlitFromCpuFilledBufferToFbo) {
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
android_native_buffer_t* anb;
- ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+ ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(),
+ &anb));
ASSERT_TRUE(anb != NULL);
sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
- ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
// Fill the buffer with green
uint8_t* img = NULL;
@@ -2146,7 +2152,8 @@ TEST_F(SurfaceTextureFBOTest, BlitFromCpuFilledBufferToFbo) {
fillRGBA8BufferSolid(img, texWidth, texHeight, buf->getStride(), 0, 255,
0, 255);
buf->unlock();
- ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
+ ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(),
+ -1));
ASSERT_EQ(NO_ERROR, mST->updateTexImage());
@@ -2157,12 +2164,11 @@ TEST_F(SurfaceTextureFBOTest, BlitFromCpuFilledBufferToFbo) {
for (int i = 0; i < 4; i++) {
SCOPED_TRACE(String8::format("frame %d", i).string());
- ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+ ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(),
+ &anb));
ASSERT_TRUE(anb != NULL);
buf = new GraphicBuffer(anb, false);
- ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(),
- buf->getNativeBuffer()));
// Fill the buffer with red
ASSERT_EQ(NO_ERROR, buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN,
@@ -2171,7 +2177,7 @@ TEST_F(SurfaceTextureFBOTest, BlitFromCpuFilledBufferToFbo) {
0, 255);
ASSERT_EQ(NO_ERROR, buf->unlock());
ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(),
- buf->getNativeBuffer()));
+ buf->getNativeBuffer(), -1));
ASSERT_EQ(NO_ERROR, mST->updateTexImage());
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index b585d68..5046bf5 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -97,22 +97,23 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) {
ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(anw.get(), 3));
ANativeWindowBuffer* buf = 0;
- status_t err = anw->dequeueBuffer(anw.get(), &buf);
+ status_t err = native_window_dequeue_buffer_and_wait(anw.get(), &buf);
if (err) {
// we could fail if GRALLOC_USAGE_PROTECTED is not supported.
// that's okay as long as this is the reason for the failure.
// try again without the GRALLOC_USAGE_PROTECTED bit.
ASSERT_EQ(NO_ERROR, native_window_set_usage(anw.get(), 0));
- ASSERT_EQ(NO_ERROR, anw->dequeueBuffer(anw.get(), &buf));
+ ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(anw.get(),
+ &buf));
return;
}
- ASSERT_EQ(NO_ERROR, anw->cancelBuffer(anw.get(), buf));
+ ASSERT_EQ(NO_ERROR, anw->cancelBuffer(anw.get(), buf, -1));
for (int i = 0; i < 4; i++) {
// Loop to make sure SurfaceFlinger has retired a protected buffer.
- ASSERT_EQ(NO_ERROR, anw->dequeueBuffer(anw.get(), &buf));
- ASSERT_EQ(NO_ERROR, anw->lockBuffer(anw.get(), buf));
- ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf));
+ ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(anw.get(),
+ &buf));
+ ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf, -1));
}
heap = 0;
w = h = fmt = 0;
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index 5aff7a4..80c28a1 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -16,6 +16,7 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ Fence.cpp \
FramebufferNativeWindow.cpp \
GraphicBuffer.cpp \
GraphicBufferAllocator.cpp \
@@ -26,8 +27,9 @@ LOCAL_SRC_FILES:= \
LOCAL_SHARED_LIBRARIES := \
libcutils \
- libutils \
- libhardware
+ libhardware \
+ libsync \
+ libutils
ifneq ($(BOARD_FRAMEBUFFER_FORCE_FORMAT),)
LOCAL_CFLAGS += -DFRAMEBUFFER_FORCE_FORMAT=$(BOARD_FRAMEBUFFER_FORCE_FORMAT)
diff --git a/libs/ui/Fence.cpp b/libs/ui/Fence.cpp
new file mode 100644
index 0000000..5c17d10
--- /dev/null
+++ b/libs/ui/Fence.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Fence"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+//#define LOG_NDEBUG 0
+
+#include <sync/sync.h>
+#include <ui/Fence.h>
+#include <unistd.h>
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+namespace android {
+
+const sp<Fence> Fence::NO_FENCE = sp<Fence>();
+
+Fence::Fence() :
+ mFenceFd(-1) {
+}
+
+Fence::Fence(int fenceFd) :
+ mFenceFd(fenceFd) {
+}
+
+Fence::~Fence() {
+ if (mFenceFd != -1) {
+ close(mFenceFd);
+ }
+}
+
+int Fence::wait(unsigned int timeout) {
+ ATRACE_CALL();
+ if (mFenceFd == -1) {
+ return NO_ERROR;
+ }
+ return sync_wait(mFenceFd, timeout);
+}
+
+sp<Fence> Fence::merge(const String8& name, const sp<Fence>& f1,
+ const sp<Fence>& f2) {
+ ATRACE_CALL();
+ int result = sync_merge(name.string(), f1->mFenceFd, f2->mFenceFd);
+ if (result == -1) {
+ ALOGE("merge: sync_merge returned an error: %s (%d)", strerror(-errno),
+ errno);
+ return NO_FENCE;
+ }
+ return sp<Fence>(new Fence(result));
+}
+
+size_t Fence::getFlattenedSize() const {
+ return 0;
+}
+
+size_t Fence::getFdCount() const {
+ return 1;
+}
+
+status_t Fence::flatten(void* buffer, size_t size, int fds[],
+ size_t count) const {
+ if (size != 0 || count != 1) {
+ return BAD_VALUE;
+ }
+
+ fds[0] = mFenceFd;
+ return NO_ERROR;
+}
+
+status_t Fence::unflatten(void const* buffer, size_t size, int fds[],
+ size_t count) {
+ if (size != 0 || count != 1) {
+ return BAD_VALUE;
+ }
+ if (mFenceFd != -1) {
+ // Don't unflatten if we already have a valid fd.
+ return INVALID_OPERATION;
+ }
+
+ mFenceFd = fds[0];
+ return NO_ERROR;
+}
+
+} // namespace android
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index dec99b6..5a36c3b 100644
--- a/libs/ui/FramebufferNativeWindow.cpp
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -28,6 +28,7 @@
#include <utils/RefBase.h>
#include <ui/ANativeObjectBase.h>
+#include <ui/Fence.h>
#include <ui/FramebufferNativeWindow.h>
#include <ui/Rect.h>
@@ -145,10 +146,13 @@ FramebufferNativeWindow::FramebufferNativeWindow()
ANativeWindow::setSwapInterval = setSwapInterval;
ANativeWindow::dequeueBuffer = dequeueBuffer;
- ANativeWindow::lockBuffer = lockBuffer;
ANativeWindow::queueBuffer = queueBuffer;
ANativeWindow::query = query;
ANativeWindow::perform = perform;
+
+ ANativeWindow::dequeueBuffer_DEPRECATED = dequeueBuffer_DEPRECATED;
+ ANativeWindow::lockBuffer_DEPRECATED = lockBuffer_DEPRECATED;
+ ANativeWindow::queueBuffer_DEPRECATED = queueBuffer_DEPRECATED;
}
FramebufferNativeWindow::~FramebufferNativeWindow()
@@ -207,9 +211,24 @@ int FramebufferNativeWindow::getCurrentBufferIndex() const
return index;
}
-int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window,
+int FramebufferNativeWindow::dequeueBuffer_DEPRECATED(ANativeWindow* window,
ANativeWindowBuffer** buffer)
{
+ int fenceFd = -1;
+ int result = dequeueBuffer(window, buffer, &fenceFd);
+ sp<Fence> fence(new Fence(fenceFd));
+ int waitResult = fence->wait(Fence::TIMEOUT_NEVER);
+ if (waitResult != OK) {
+ ALOGE("dequeueBuffer_DEPRECATED: Fence::wait returned an "
+ "error: %d", waitResult);
+ return waitResult;
+ }
+ return result;
+}
+
+int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window,
+ ANativeWindowBuffer** buffer, int* fenceFd)
+{
FramebufferNativeWindow* self = getSelf(window);
Mutex::Autolock _l(self->mutex);
framebuffer_device_t* fb = self->fbDev;
@@ -218,43 +237,45 @@ int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window,
if (self->mBufferHead >= self->mNumBuffers)
self->mBufferHead = 0;
- // wait for a free buffer
- while (!self->mNumFreeBuffers) {
+ // wait for a free non-front buffer
+ while (self->mNumFreeBuffers < 2) {
self->mCondition.wait(self->mutex);
}
+ ALOG_ASSERT(self->buffers[index] != self->front);
+
// get this buffer
self->mNumFreeBuffers--;
self->mCurrentBufferIndex = index;
*buffer = self->buffers[index].get();
+ *fenceFd = -1;
return 0;
}
-int FramebufferNativeWindow::lockBuffer(ANativeWindow* window,
+int FramebufferNativeWindow::lockBuffer_DEPRECATED(ANativeWindow* window,
ANativeWindowBuffer* buffer)
{
- FramebufferNativeWindow* self = getSelf(window);
- Mutex::Autolock _l(self->mutex);
-
- const int index = self->mCurrentBufferIndex;
-
- // wait that the buffer we're locking is not front anymore
- while (self->front == buffer) {
- self->mCondition.wait(self->mutex);
- }
-
return NO_ERROR;
}
-int FramebufferNativeWindow::queueBuffer(ANativeWindow* window,
+int FramebufferNativeWindow::queueBuffer_DEPRECATED(ANativeWindow* window,
ANativeWindowBuffer* buffer)
{
+ return queueBuffer(window, buffer, -1);
+}
+
+int FramebufferNativeWindow::queueBuffer(ANativeWindow* window,
+ ANativeWindowBuffer* buffer, int fenceFd)
+{
FramebufferNativeWindow* self = getSelf(window);
Mutex::Autolock _l(self->mutex);
framebuffer_device_t* fb = self->fbDev;
buffer_handle_t handle = static_cast<NativeBuffer*>(buffer)->handle;
+ sp<Fence> fence(new Fence(fenceFd));
+ fence->wait(Fence::TIMEOUT_NEVER);
+
const int index = self->mCurrentBufferIndex;
int res = fb->post(fb, handle);
self->front = static_cast<NativeBuffer*>(buffer);
diff --git a/libs/utils/ZipFileRO.cpp b/libs/utils/ZipFileRO.cpp
index cad7720..db17546 100644
--- a/libs/utils/ZipFileRO.cpp
+++ b/libs/utils/ZipFileRO.cpp
@@ -118,7 +118,7 @@ ZipFileRO::~ZipFileRO() {
*/
int ZipFileRO::entryToIndex(const ZipEntryRO entry) const
{
- long ent = ((long) entry) - kZipEntryAdj;
+ long ent = ((intptr_t) entry) - kZipEntryAdj;
if (ent < 0 || ent >= mHashTableSize || mHashTable[ent].name == NULL) {
ALOGW("Invalid ZipEntryRO %p (%ld)\n", entry, ent);
return -1;
@@ -459,7 +459,7 @@ ZipEntryRO ZipFileRO::findEntryByIndex(int idx) const
for (int ent = 0; ent < mHashTableSize; ent++) {
if (mHashTable[ent].name != NULL) {
if (idx-- == 0)
- return (ZipEntryRO) (ent + kZipEntryAdj);
+ return (ZipEntryRO) (intptr_t)(ent + kZipEntryAdj);
}
}
diff --git a/opengl/libagl/Android.mk b/opengl/libagl/Android.mk
index 15e58f2..639c4d7 100644
--- a/opengl/libagl/Android.mk
+++ b/opengl/libagl/Android.mk
@@ -26,7 +26,7 @@ LOCAL_CFLAGS += -DLOG_TAG=\"libagl\"
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
LOCAL_CFLAGS += -fvisibility=hidden
-LOCAL_SHARED_LIBRARIES := libcutils libhardware libutils libpixelflinger libETC1
+LOCAL_SHARED_LIBRARIES := libcutils libhardware libutils libpixelflinger libETC1 libui
LOCAL_LDLIBS := -lpthread -ldl
ifeq ($(TARGET_ARCH),arm)
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index c31aebf..172ef95 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -31,6 +31,7 @@
#include <utils/threads.h>
#include <ui/ANativeObjectBase.h>
+#include <ui/Fence.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
@@ -372,7 +373,16 @@ EGLBoolean egl_window_surface_v2_t::connect()
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
// dequeue a buffer
- if (nativeWindow->dequeueBuffer(nativeWindow, &buffer) != NO_ERROR) {
+ int fenceFd = -1;
+ if (nativeWindow->dequeueBuffer(nativeWindow, &buffer,
+ &fenceFd) != NO_ERROR) {
+ return setError(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+
+ // wait for the buffer
+ sp<Fence> fence(new Fence(fenceFd));
+ if (fence->wait(Fence::TIMEOUT_NEVER) != NO_ERROR) {
+ nativeWindow->cancelBuffer(nativeWindow, buffer, fenceFd);
return setError(EGL_BAD_ALLOC, EGL_FALSE);
}
@@ -392,8 +402,6 @@ EGLBoolean egl_window_surface_v2_t::connect()
// keep a reference on the buffer
buffer->common.incRef(&buffer->common);
- // Lock the buffer
- nativeWindow->lockBuffer(nativeWindow, buffer);
// pin the buffer down
if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |
GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
@@ -412,7 +420,7 @@ void egl_window_surface_v2_t::disconnect()
unlock(buffer);
}
// enqueue the last frame
- nativeWindow->queueBuffer(nativeWindow, buffer);
+ nativeWindow->queueBuffer(nativeWindow, buffer, -1);
if (buffer) {
buffer->common.decRef(&buffer->common);
buffer = 0;
@@ -517,15 +525,17 @@ EGLBoolean egl_window_surface_v2_t::swapBuffers()
unlock(buffer);
previousBuffer = buffer;
- nativeWindow->queueBuffer(nativeWindow, buffer);
+ nativeWindow->queueBuffer(nativeWindow, buffer, -1);
buffer = 0;
// dequeue a new buffer
- if (nativeWindow->dequeueBuffer(nativeWindow, &buffer) == NO_ERROR) {
-
- // TODO: lockBuffer should rather be executed when the very first
- // direct rendering occurs.
- nativeWindow->lockBuffer(nativeWindow, buffer);
+ int fenceFd = -1;
+ if (nativeWindow->dequeueBuffer(nativeWindow, &buffer, &fenceFd) == NO_ERROR) {
+ sp<Fence> fence(new Fence(fenceFd));
+ if (fence->wait(Fence::TIMEOUT_NEVER)) {
+ nativeWindow->cancelBuffer(nativeWindow, buffer, fenceFd);
+ return setError(EGL_BAD_ALLOC, EGL_FALSE);
+ }
// reallocate the depth-buffer if needed
if ((width != buffer->width) || (height != buffer->height)) {
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index a46aa38..80072ab 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -263,7 +263,13 @@ EGLBoolean egl_display_t::terminate() {
Mutex::Autolock _l(lock);
if (refs == 0) {
- return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
+ /*
+ * From the EGL spec (3.2):
+ * "Termination of a display that has already been terminated,
+ * (...), is allowed, but the only effect of such a call is
+ * to return EGL_TRUE (...)
+ */
+ return EGL_TRUE;
}
// this is specific to Android, display termination is ref-counted.
diff --git a/opengl/libs/GLES_trace/src/gltrace_context.cpp b/opengl/libs/GLES_trace/src/gltrace_context.cpp
index 45dbb43..91b291e 100644
--- a/opengl/libs/GLES_trace/src/gltrace_context.cpp
+++ b/opengl/libs/GLES_trace/src/gltrace_context.cpp
@@ -119,7 +119,7 @@ GLTraceContext *GLTraceState::createTraceContext(int version, EGLContext eglCont
const size_t DEFAULT_BUFFER_SIZE = 8192;
BufferedOutputStream *stream = new BufferedOutputStream(mStream, DEFAULT_BUFFER_SIZE);
- GLTraceContext *traceContext = new GLTraceContext(id, this, stream);
+ GLTraceContext *traceContext = new GLTraceContext(id, version, this, stream);
mPerContextState[eglContext] = traceContext;
return traceContext;
@@ -129,8 +129,10 @@ GLTraceContext *GLTraceState::getTraceContext(EGLContext c) {
return mPerContextState[c];
}
-GLTraceContext::GLTraceContext(int id, GLTraceState *state, BufferedOutputStream *stream) :
+GLTraceContext::GLTraceContext(int id, int version, GLTraceState *state,
+ BufferedOutputStream *stream) :
mId(id),
+ mVersion(version),
mState(state),
mBufferedOutputStream(stream),
mElementArrayBuffers(DefaultKeyedVector<GLuint, ElementArrayBuffer*>(NULL))
@@ -143,6 +145,10 @@ int GLTraceContext::getId() {
return mId;
}
+int GLTraceContext::getVersion() {
+ return mVersion;
+}
+
GLTraceState *GLTraceContext::getGlobalTraceState() {
return mState;
}
diff --git a/opengl/libs/GLES_trace/src/gltrace_context.h b/opengl/libs/GLES_trace/src/gltrace_context.h
index 323cfdc..4c38bba 100644
--- a/opengl/libs/GLES_trace/src/gltrace_context.h
+++ b/opengl/libs/GLES_trace/src/gltrace_context.h
@@ -50,6 +50,7 @@ public:
/** GL Trace Context info associated with each EGLContext */
class GLTraceContext {
int mId; /* unique context id */
+ int mVersion; /* GL version, e.g: egl_connection_t::GLESv2_INDEX */
GLTraceState *mState; /* parent GL Trace state (for per process GL Trace State Info) */
void *fbcontents; /* memory area to read framebuffer contents */
@@ -65,8 +66,9 @@ class GLTraceContext {
public:
gl_hooks_t *hooks;
- GLTraceContext(int id, GLTraceState *state, BufferedOutputStream *stream);
+ GLTraceContext(int id, int version, GLTraceState *state, BufferedOutputStream *stream);
int getId();
+ int getVersion();
GLTraceState *getGlobalTraceState();
void getCompressedFB(void **fb, unsigned *fbsize,
unsigned *fbwidth, unsigned *fbheight,
diff --git a/opengl/libs/GLES_trace/src/gltrace_fixup.cpp b/opengl/libs/GLES_trace/src/gltrace_fixup.cpp
index 3597b26..1bd790e 100644
--- a/opengl/libs/GLES_trace/src/gltrace_fixup.cpp
+++ b/opengl/libs/GLES_trace/src/gltrace_fixup.cpp
@@ -15,6 +15,7 @@
*/
#include <cutils/log.h>
+#include <EGL/egldefs.h>
#include <GLES/gl.h>
#include <GLES/glext.h>
#include <GLES2/gl2.h>
@@ -592,6 +593,11 @@ void trace_VertexAttribPointerData(GLTraceContext *context,
}
void trace_VertexAttribPointerDataForGlDrawArrays(GLTraceContext *context, GLMessage *glmsg) {
+ if (context->getVersion() == egl_connection_t::GLESv1_INDEX) {
+ // only supported for GLES2 and above
+ return;
+ }
+
/* void glDrawArrays(GLenum mode, GLint first, GLsizei count) */
GLsizei count = glmsg->args(2).intvalue(0);
@@ -604,6 +610,11 @@ void trace_VertexAttribPointerDataForGlDrawArrays(GLTraceContext *context, GLMes
void trace_VertexAttribPointerDataForGlDrawElements(GLTraceContext *context, GLMessage *glmsg,
GLvoid *indices) {
+ if (context->getVersion() == egl_connection_t::GLESv1_INDEX) {
+ // only supported for GLES2 and above
+ return;
+ }
+
/* void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) */
GLsizei count = glmsg->args(1).intvalue(0);
GLenum type = glmsg->args(2).intvalue(0);
diff --git a/opengl/specs/EGL_ANDROID_fence_sync.txt b/opengl/specs/EGL_ANDROID_fence_sync.txt
new file mode 100644
index 0000000..bb618c9
--- /dev/null
+++ b/opengl/specs/EGL_ANDROID_fence_sync.txt
@@ -0,0 +1,213 @@
+Name
+
+ ANDROID_fence_sync
+
+Name Strings
+
+ EGL_ANDROID_fence_sync
+
+Contributors
+
+ Jamie Gennis
+
+Contact
+
+ Jamie Gennis, Google Inc. (jgennis 'at' google.com)
+
+Status
+
+ Draft.
+
+Version
+
+ Version 1, May 29, 2012
+
+Number
+
+ EGL Extension #XXX
+
+Dependencies
+
+ Requires EGL 1.1
+
+ This extension is written against the wording of the EGL 1.2 Specification
+
+ EGL_KHR_fence_sync is required.
+
+Overview
+
+ This extension enables the creation of EGL fence sync objects that are
+ associated with an Android Sync HAL fence object. These EGL fence sync
+ objects have nearly identical semantics to those defined by the
+ KHR_fence_sync extension, except that they have an additional attribute
+ storing the file descriptor referring to the native Android fence object.
+
+New Types
+
+ None.
+
+New Procedures and Functions
+
+ None.
+
+New Tokens
+
+ Accepted by the <type> parameter of eglCreateSyncKHR, and returned
+ in <value> when eglGetSyncAttribKHR is called with <attribute>
+ EGL_SYNC_TYPE_KHR:
+
+ EGL_SYNC_ANDROID_FENCE_ANDROID 0x3144
+
+ Accepted by the <attribute> parameter of eglGetSyncAttribKHR:
+
+ EGL_SYNC_FENCE_FD_ANDROID 0x3145
+
+ Returned in <value> when eglGetSyncAttribKHR is called with <attribute>
+ EGL_SYNC_CONDITION_KHR:
+
+ EGL_SYNC_ANDROID_FENCE_SIGNALED_ANDROID 0x3146
+
+Changes to Chapter 3 of the EGL 1.2 Specification (EGL Functions and Errors)
+
+ Add the following after the sixth paragraph of Section 3.8.1 (Sync
+ Objects), added by KHR_fence_sync
+
+ "If <type> is EGL_SYNC_ANDROID_FENCE_ANDROID, an EGL Android fence sync
+ object is created. In this case the EGL_SYNC_FENCE_FD_ANDROID attribute may
+ optionally be specified. If this attribute is specified, it must be set to
+ a file descriptor that refers to a native Android fence object.
+
+ The default values for the EGL Android fence sync object attributes are as
+ follows:
+
+ Attribute Name Initial Attribute Value(s)
+ --------------- --------------------------
+ EGL_SYNC_TYPE_KHR EGL_SYNC_ANDROID_FENCE_ANDROID
+ EGL_SYNC_STATUS_KHR EGL_UNSIGNALED_KHR
+ EGL_SYNC_CONDITION_KHR EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR
+
+ Upon creation of an EGL Android fence sync object, the
+ EGL_SYNC_FENCE_FD_ANDROID attribute is set to a newly generated file
+ descriptor that refers to a native Android fence object. If the
+ EGL_SYNC_FENCE_FD_ANDROID attribute is specified in the eglCreateSyncKHR
+ call then the generated file descriptor refers to the same native Android
+ fence object as the file descriptor passed to eglCreateSyncKHR. Note,
+ however, that the value of the sync object attribute is *not* the same file
+ descriptor as the one passed to eglCreateSyncKHR - it simply refers to the
+ same underlying native Android fence object. Additionally, if the
+ EGL_SYNC_FENCE_FD_ANDROID attribute is specified then the
+ EGL_SYNC_CONDITION_KHR attribute is set to
+ EGL_SYNC_ANDROID_FENCE_SIGNALED_ANDROID and the EGL_SYNC_STATUS_KHR
+ attribute is set to reflect the signal status of the native Android fence
+ object."
+
+ Modify Section 3.8.1 (Sync Objects), added by KHR_fence_sync, starting at
+ the seventh paragraph
+
+ "When a fence sync object is created or when an EGL Android fence sync
+ object is created without specifying the EGL_SYNC_FENCE_FD_ANDROID
+ attribute, eglCreateSyncKHR also inserts a fence command into the command
+ stream of the bound client API's current context (i.e., the context
+ returned by eglGetCurrentContext), and associates it with the newly created
+ sync object.
+
+ When the condition of the sync object is satisfied by the fence command,
+ the sync is signaled by the associated client API context, causing any
+ eglClientWaitSyncKHR commands (see below) blocking on <sync> to unblock. If
+ the sync object is an EGL Android fence sync object then the native Android
+ fence object is also signaled when the condition is satisfied. The
+ EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR condition is satisfied by completion
+ of the fence command corresponding to the sync object and all preceding
+ commands in the associated client API context's command stream. The sync
+ object will not be signaled until all effects from these commands on the
+ client API's internal and framebuffer state are fully realized. No other
+ state is affected by execution of the fence command.
+
+ The EGL_SYNC_ANDROID_FENCE_SIGNALED_ANDROID condition is satisfied by the
+ signaling of the native Android fence object. When this happens any
+ eglClientWaitSyncKHR commands blocking on <sync> unblock."
+
+ Modify the list of eglCreateSyncKHR errors in Section 3.8.1 (Sync Objects),
+ added by KHR_fence_sync
+
+ "Errors
+ ------
+
+ * If <dpy> is not the name of a valid, initialized EGLDisplay,
+ EGL_NO_SYNC_KHR is returned and an EGL_BAD_DISPLAY error is
+ generated.
+ * If <type> is EGL_SYNC_FENCE_KHR and <attrib_list> is neither NULL nor
+ empty (containing only EGL_NONE), EGL_NO_SYNC_KHR is returned and an
+ EGL_BAD_ATTRIBUTE error is generated.
+ * If <type> is EGL_SYNC_ANDROID_FENCE_ANDROID and <attrib_list> contains
+ an attribute other than EGL_SYNC_FENCE_FD_ANDROID, EGL_NO_SYNC_KHR is
+ returned and an EGL_BAD_ATTRIBUTE error is generated.
+ * If <type> is not a supported type of sync object,
+ EGL_NO_SYNC_KHR is returned and an EGL_BAD_ATTRIBUTE error is
+ generated.
+ * If <type> is EGL_SYNC_FENCE_KHR or EGL_SYNC_ANDROID_FENCE_ANDROID and
+ no context is current for the bound API (i.e., eglGetCurrentContext
+ returns EGL_NO_CONTEXT), EGL_NO_SYNC_KHR is returned and an
+ EGL_BAD_MATCH error is generated.
+ * If <type> is EGL_SYNC_FENCE_KHR or EGL_SYNC_ANDROID_FENCE_ANDROID and
+ <dpy> does not match the EGLDisplay of the currently bound context for
+ the currently bound client API (the EGLDisplay returned by
+ eglGetCurrentDisplay()) then EGL_NO_SYNC_KHR is returned and an
+ EGL_BAD_MATCH error is generated.
+ * If <type> is EGL_SYNC_FENCE_KHR or EGL_SYNC_ANDROID_FENCE_ANDROID and
+ the currently bound client API does not support the client API
+ extension indicating it can place fence commands, then EGL_NO_SYNC_KHR
+ is returned and an EGL_BAD_MATCH error is generated."
+
+ Modify table 3.cc in Section 3.8.1 (Sync Objects), added by KHR_fence_sync
+
+ "
+ Attribute Description Supported Sync Objects
+ ----------------- ----------------------- ----------------------
+ EGL_SYNC_TYPE_KHR Type of the sync object All
+ EGL_SYNC_STATUS_KHR Status of the sync object All
+ EGL_SYNC_CONDITION_KHR Signaling condition EGL_SYNC_FENCE_KHR and
+ EGL_SYNC_ANDROID_FENCE_ANDROID only
+ EGL_SYNC_FENCE_FD_ANDROID Native Android fence EGL_SYNC_ANDROID_FENCE_ANDROID only
+ object file descriptor
+ "
+
+ Modify the second paragraph description of eglDestroySyncKHR in Section
+ 3.8.1 (Sync Objects), added by KHR_fence_sync
+
+ "If no errors are generated, EGL_TRUE is returned, and <sync> will no
+ longer be the handle of a valid sync object. Additionally, if <sync> is an
+ EGL Android fence sync object then the file descriptor stored in the
+ EGL_SYNC_FENCE_FD_ANDROID attribute is closed and is no longer a valid file
+ descriptor."
+
+Issues
+
+ 1. Should EGLSyncKHR objects that wrap Android fence objects use the
+ EGL_SYNC_FENCE_KHR type?
+
+ RESOLVED: A new sync object type will be added.
+
+ We don't want to require all EGL fence sync objects to wrap Android fence
+ objects, so we need some way to tell the EGL implementation at sync object
+ creation whether the sync object should support querying the Android fence
+ FD attribute. We could do this with either a new sync object type or with a
+ boolean attribute. It might be nice to pick up future signaling conditions
+ that might be added for fence sync objects, but there may be things that
+ get added that don't make sense in the context of Android fence objects.
+
+ 2. Who is responsible for dup'ing the Android fence file descriptors?
+
+ RESOLVED: The recipient of a file descriptor is responsible for dup'ing it
+ if it wishes to maintain a reference to the Android fence object.
+
+ This means that when eglCreateSyncKHR is called with an existing file
+ descriptor, the EGL implementation must dup it. On the other hand, when
+ eglGetSyncAttribKHR is called to query the file descriptor, it is the
+ responsibility of the caller to dup the file descriptor if it wishes to
+ maintain a reference that will outlast the EGLSyncKHR object.
+
+Revision History
+
+#1 (Jamie Gennis, May 29, 2012)
+ - Initial draft.
diff --git a/opengl/specs/README b/opengl/specs/README
index 16b278f..af3f165 100644
--- a/opengl/specs/README
+++ b/opengl/specs/README
@@ -10,4 +10,7 @@ for use by Android extensions.
0x3141 (unused)
0x3142 EGL_ANDROID_recordable
0x3143 EGL_VERSION_HW_ANDROID (internal use)
-0x3144 - 0x314F (unused)
+0x3144 EGL_SYNC_ANDROID_FENCE_ANDROID
+0x3145 EGL_SYNC_FENCE_FD_ANDROID
+0x3146 EGL_SYNC_ANDROID_FENCE_SIGNALED_ANDROID
+0x3147 - 0x314F (unused)
diff --git a/opengl/tests/hwc/hwcColorEquiv.cpp b/opengl/tests/hwc/hwcColorEquiv.cpp
index bb305dc..ab5277e 100644
--- a/opengl/tests/hwc/hwcColorEquiv.cpp
+++ b/opengl/tests/hwc/hwcColorEquiv.cpp
@@ -124,7 +124,7 @@ const float defaultEndDelay = 2.0; // Default delay after rendering graphics
// Globals
static const int texUsage = GraphicBuffer::USAGE_HW_TEXTURE |
GraphicBuffer::USAGE_SW_WRITE_RARELY;
-static hwc_composer_device_t *hwcDevice;
+static hwc_composer_device_1_t *hwcDevice;
static EGLDisplay dpy;
static EGLSurface surface;
static EGLint width, height;
@@ -344,16 +344,16 @@ main(int argc, char *argv[])
hwcTestFillColorHBlend(equivFrame.get(), refFormat->format,
startRefColor, endRefColor);
- hwc_layer_list_t *list;
- size_t size = sizeof(hwc_layer_list) + numFrames * sizeof(hwc_layer_t);
- if ((list = (hwc_layer_list_t *) calloc(1, size)) == NULL) {
+ hwc_layer_list_1_t *list;
+ size_t size = sizeof(hwc_layer_list_1_t) + numFrames * sizeof(hwc_layer_1_t);
+ if ((list = (hwc_layer_list_1_t *) calloc(1, size)) == NULL) {
testPrintE("Allocate list failed");
exit(11);
}
list->flags = HWC_GEOMETRY_CHANGED;
list->numHwLayers = numFrames;
- hwc_layer_t *layer = &list->hwLayers[0];
+ hwc_layer_1_t *layer = &list->hwLayers[0];
layer->handle = refFrame->handle;
layer->blending = HWC_BLENDING_NONE;
layer->sourceCrop.left = 0;
diff --git a/opengl/tests/hwc/hwcCommit.cpp b/opengl/tests/hwc/hwcCommit.cpp
index efa646c..d4873d8 100644
--- a/opengl/tests/hwc/hwcCommit.cpp
+++ b/opengl/tests/hwc/hwcCommit.cpp
@@ -230,7 +230,7 @@ private:
// Globals
static const int texUsage = GraphicBuffer::USAGE_HW_TEXTURE |
GraphicBuffer::USAGE_SW_WRITE_RARELY;
-static hwc_composer_device_t *hwcDevice;
+static hwc_composer_device_1_t *hwcDevice;
static EGLDisplay dpy;
static EGLSurface surface;
static EGLint width, height;
@@ -1397,7 +1397,7 @@ void Rational::double2Rational(double f, Range nRange, Range dRange,
// Given a list of rectangles, determine how many HWC will commit to render
uint32_t numOverlays(list<Rectangle>& rectList)
{
- hwc_layer_list_t *hwcList;
+ hwc_layer_list_1_t *hwcList;
list<sp<GraphicBuffer> > buffers;
hwcList = hwcTestCreateLayerList(rectList.size());
@@ -1406,7 +1406,7 @@ uint32_t numOverlays(list<Rectangle>& rectList)
exit(30);
}
- hwc_layer_t *layer = &hwcList->hwLayers[0];
+ hwc_layer_1_t *layer = &hwcList->hwLayers[0];
for (std::list<Rectangle>::iterator it = rectList.begin();
it != rectList.end(); ++it, ++layer) {
// Allocate the texture for the source frame
diff --git a/opengl/tests/hwc/hwcRects.cpp b/opengl/tests/hwc/hwcRects.cpp
index 906c169..e2f0039 100644
--- a/opengl/tests/hwc/hwcRects.cpp
+++ b/opengl/tests/hwc/hwcRects.cpp
@@ -165,7 +165,7 @@ public:
list<Rectangle> rectangle;
static const int texUsage = GraphicBuffer::USAGE_HW_TEXTURE |
GraphicBuffer::USAGE_SW_WRITE_RARELY;
-static hwc_composer_device_t *hwcDevice;
+static hwc_composer_device_1_t *hwcDevice;
static EGLDisplay dpy;
static EGLSurface surface;
static EGLint width, height;
@@ -307,14 +307,14 @@ main(int argc, char *argv[])
}
// Create list of frames
- hwc_layer_list_t *list;
+ hwc_layer_list_1_t *list;
list = hwcTestCreateLayerList(rectangle.size());
if (list == NULL) {
testPrintE("hwcTestCreateLayerList failed");
exit(5);
}
- hwc_layer_t *layer = &list->hwLayers[0];
+ hwc_layer_1_t *layer = &list->hwLayers[0];
for (std::list<Rectangle>::iterator it = rectangle.begin();
it != rectangle.end(); ++it, ++layer) {
layer->handle = it->texture->handle;
diff --git a/opengl/tests/hwc/hwcStress.cpp b/opengl/tests/hwc/hwcStress.cpp
index b02a424..ccc7328 100644
--- a/opengl/tests/hwc/hwcStress.cpp
+++ b/opengl/tests/hwc/hwcStress.cpp
@@ -192,7 +192,7 @@ const vector<unsigned int> vecTransformFlags(transformFlags,
// File scope globals
static const int texUsage = GraphicBuffer::USAGE_HW_TEXTURE |
GraphicBuffer::USAGE_SW_WRITE_RARELY;
-static hwc_composer_device_t *hwcDevice;
+static hwc_composer_device_1_t *hwcDevice;
static EGLDisplay dpy;
static EGLSurface surface;
static EGLint width, height;
@@ -409,7 +409,7 @@ main(int argc, char *argv[])
// generated for this pass.
srand48(pass);
- hwc_layer_list_t *list;
+ hwc_layer_list_1_t *list;
list = hwcTestCreateLayerList(testRandMod(frames.size()) + 1);
if (list == NULL) {
testPrintE("hwcTestCreateLayerList failed");
@@ -428,7 +428,7 @@ main(int argc, char *argv[])
for (unsigned int n1 = 0; n1 < list->numHwLayers; n1++) {
unsigned int idx = testRandMod(selectedFrames[n1].size());
sp<GraphicBuffer> gBuf = selectedFrames[n1][idx];
- hwc_layer_t *layer = &list->hwLayers[n1];
+ hwc_layer_1_t *layer = &list->hwLayers[n1];
layer->handle = gBuf->handle;
layer->blending = blendingOps[testRandMod(NUMA(blendingOps))];
@@ -497,7 +497,7 @@ main(int argc, char *argv[])
for (unsigned int n1 = 0; n1 < list->numHwLayers; n1++) {
unsigned int idx = testRandMod(selectedFrames[n1].size());
sp<GraphicBuffer> gBuf = selectedFrames[n1][idx];
- hwc_layer_t *layer = &list->hwLayers[n1];
+ hwc_layer_1_t *layer = &list->hwLayers[n1];
layer->handle = (native_handle_t *) gBuf->handle;
}
diff --git a/opengl/tests/hwc/hwcTestLib.cpp b/opengl/tests/hwc/hwcTestLib.cpp
index 28e0c3f..c6dbe9d 100644
--- a/opengl/tests/hwc/hwcTestLib.cpp
+++ b/opengl/tests/hwc/hwcTestLib.cpp
@@ -134,7 +134,7 @@ void hwcTestInitDisplay(bool verbose, EGLDisplay *dpy, EGLSurface *surface,
}
// Open Hardware Composer Device
-void hwcTestOpenHwc(hwc_composer_device_t **hwcDevicePtr)
+void hwcTestOpenHwc(hwc_composer_device_1_t **hwcDevicePtr)
{
int rv;
hw_module_t const *hwcModule;
@@ -145,7 +145,7 @@ void hwcTestOpenHwc(hwc_composer_device_t **hwcDevicePtr)
perror(NULL);
exit(77);
}
- if ((rv = hwc_open(hwcModule, hwcDevicePtr)) != 0) {
+ if ((rv = hwc_open_1(hwcModule, hwcDevicePtr)) != 0) {
testPrintE("hwc_open failed, rv: %i", rv);
errno = -rv;
perror(NULL);
@@ -399,12 +399,12 @@ const char *hwcTestGraphicFormat2str(uint32_t format)
* Dynamically creates layer list with numLayers worth
* of hwLayers entries.
*/
-hwc_layer_list_t *hwcTestCreateLayerList(size_t numLayers)
+hwc_layer_list_1_t *hwcTestCreateLayerList(size_t numLayers)
{
- hwc_layer_list_t *list;
+ hwc_layer_list_1_t *list;
- size_t size = sizeof(hwc_layer_list) + numLayers * sizeof(hwc_layer_t);
- if ((list = (hwc_layer_list_t *) calloc(1, size)) == NULL) {
+ size_t size = sizeof(hwc_layer_list_1_t) + numLayers * sizeof(hwc_layer_1_t);
+ if ((list = (hwc_layer_list_1_t *) calloc(1, size)) == NULL) {
return NULL;
}
list->flags = HWC_GEOMETRY_CHANGED;
@@ -417,13 +417,13 @@ hwc_layer_list_t *hwcTestCreateLayerList(size_t numLayers)
* hwcTestFreeLayerList
* Frees memory previous allocated via hwcTestCreateLayerList().
*/
-void hwcTestFreeLayerList(hwc_layer_list_t *list)
+void hwcTestFreeLayerList(hwc_layer_list_1_t *list)
{
free(list);
}
// Display the settings of the layer list pointed to by list
-void hwcTestDisplayList(hwc_layer_list_t *list)
+void hwcTestDisplayList(hwc_layer_list_1_t *list)
{
testPrintI(" flags: %#x%s", list->flags,
(list->flags & HWC_GEOMETRY_CHANGED) ? " GEOMETRY_CHANGED" : "");
@@ -494,7 +494,7 @@ void hwcTestDisplayList(hwc_layer_list_t *list)
* Displays the portions of a list that are meant to be modified by
* a prepare call.
*/
-void hwcTestDisplayListPrepareModifiable(hwc_layer_list_t *list)
+void hwcTestDisplayListPrepareModifiable(hwc_layer_list_1_t *list)
{
uint32_t numOverlays = 0;
for (unsigned int layer = 0; layer < list->numHwLayers; layer++) {
@@ -522,7 +522,7 @@ void hwcTestDisplayListPrepareModifiable(hwc_layer_list_t *list)
*
* Displays the handles of all the graphic buffers in the list.
*/
-void hwcTestDisplayListHandles(hwc_layer_list_t *list)
+void hwcTestDisplayListHandles(hwc_layer_list_1_t *list)
{
const unsigned int maxLayersPerLine = 6;
diff --git a/opengl/tests/hwc/hwcTestLib.h b/opengl/tests/hwc/hwcTestLib.h
index b0c3012..db3f5c1 100644
--- a/opengl/tests/hwc/hwcTestLib.h
+++ b/opengl/tests/hwc/hwcTestLib.h
@@ -107,17 +107,17 @@ class HwcTestDim {
// Function Prototypes
void hwcTestInitDisplay(bool verbose, EGLDisplay *dpy, EGLSurface *surface,
EGLint *width, EGLint *height);
-void hwcTestOpenHwc(hwc_composer_device_t **hwcDevicePtr);
+void hwcTestOpenHwc(hwc_composer_device_1_t **hwcDevicePtr);
const struct hwcTestGraphicFormat *hwcTestGraphicFormatLookup(const char *desc);
const struct hwcTestGraphicFormat *hwcTestGraphicFormatLookup(uint32_t id);
const char *hwcTestGraphicFormat2str(uint32_t format);
std::string hwcTestRect2str(const struct hwc_rect& rect);
-hwc_layer_list_t *hwcTestCreateLayerList(size_t numLayers);
-void hwcTestFreeLayerList(hwc_layer_list_t *list);
-void hwcTestDisplayList(hwc_layer_list_t *list);
-void hwcTestDisplayListPrepareModifiable(hwc_layer_list_t *list);
-void hwcTestDisplayListHandles(hwc_layer_list_t *list);
+hwc_layer_list_1_t *hwcTestCreateLayerList(size_t numLayers);
+void hwcTestFreeLayerList(hwc_layer_list_1_t *list);
+void hwcTestDisplayList(hwc_layer_list_1_t *list);
+void hwcTestDisplayListPrepareModifiable(hwc_layer_list_1_t *list);
+void hwcTestDisplayListHandles(hwc_layer_list_1_t *list);
uint32_t hwcTestColor2Pixel(uint32_t format, ColorFract color, float alpha);
void hwcTestColorConvert(uint32_t fromFormat, uint32_t toFormat,
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 6f7a7e1..f4bf9ef 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -2,6 +2,7 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ Client.cpp \
EventThread.cpp \
Layer.cpp \
LayerBase.cpp \
@@ -9,6 +10,7 @@ LOCAL_SRC_FILES:= \
LayerScreenshot.cpp \
DisplayHardware/DisplayHardware.cpp \
DisplayHardware/DisplayHardwareBase.cpp \
+ DisplayHardware/FramebufferSurface.cpp \
DisplayHardware/HWComposer.cpp \
DisplayHardware/PowerHAL.cpp \
GLExtensions.cpp \
@@ -21,18 +23,18 @@ LOCAL_SRC_FILES:= \
LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\"
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-ifeq ($(TARGET_BOARD_PLATFORM), omap3)
+ifeq ($(TARGET_BOARD_PLATFORM),omap3)
LOCAL_CFLAGS += -DNO_RGBX_8888
endif
-ifeq ($(TARGET_BOARD_PLATFORM), omap4)
+ifeq ($(TARGET_BOARD_PLATFORM),omap4)
LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY
endif
-ifeq ($(TARGET_BOARD_PLATFORM), s5pc110)
+ifeq ($(TARGET_BOARD_PLATFORM),s5pc110)
LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY
LOCAL_CFLAGS += -DNEVER_DEFAULT_TO_ASYNC_MODE
endif
-ifeq ($(TARGET_DISABLE_TRIPLE_BUFFERING), true)
+ifeq ($(TARGET_DISABLE_TRIPLE_BUFFERING),true)
LOCAL_CFLAGS += -DTARGET_DISABLE_TRIPLE_BUFFERING
endif
@@ -47,9 +49,9 @@ LOCAL_SHARED_LIBRARIES := \
libgui
# this is only needed for DDMS debugging
-ifneq ($(TARGET_BUILD_PDK), true)
+ifneq ($(TARGET_BUILD_PDK),true)
LOCAL_SHARED_LIBRARIES += libdvm libandroid_runtime
- LOCAL_CLFAGS += -DDDMS_DEBUGGING
+ LOCAL_CFLAGS += -DDDMS_DEBUGGING
LOCAL_SRC_FILES += DdmConnection.cpp
endif
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
new file mode 100644
index 0000000..6af1943
--- /dev/null
+++ b/services/surfaceflinger/Client.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/PermissionCache.h>
+
+#include <private/android_filesystem_config.h>
+
+#include "Client.h"
+#include "LayerBase.h"
+#include "SurfaceFlinger.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER");
+
+// ---------------------------------------------------------------------------
+
+Client::Client(const sp<SurfaceFlinger>& flinger)
+ : mFlinger(flinger), mNameGenerator(1)
+{
+}
+
+Client::~Client()
+{
+ const size_t count = mLayers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ sp<LayerBaseClient> layer(mLayers.valueAt(i).promote());
+ if (layer != 0) {
+ mFlinger->removeLayer(layer);
+ }
+ }
+}
+
+status_t Client::initCheck() const {
+ return NO_ERROR;
+}
+
+size_t Client::attachLayer(const sp<LayerBaseClient>& layer)
+{
+ Mutex::Autolock _l(mLock);
+ size_t name = mNameGenerator++;
+ mLayers.add(name, layer);
+ return name;
+}
+
+void Client::detachLayer(const LayerBaseClient* layer)
+{
+ Mutex::Autolock _l(mLock);
+ // we do a linear search here, because this doesn't happen often
+ const size_t count = mLayers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ if (mLayers.valueAt(i) == layer) {
+ mLayers.removeItemsAt(i, 1);
+ break;
+ }
+ }
+}
+sp<LayerBaseClient> Client::getLayerUser(int32_t i) const
+{
+ Mutex::Autolock _l(mLock);
+ sp<LayerBaseClient> lbc;
+ wp<LayerBaseClient> layer(mLayers.valueFor(i));
+ if (layer != 0) {
+ lbc = layer.promote();
+ ALOGE_IF(lbc==0, "getLayerUser(name=%d) is dead", int(i));
+ }
+ return lbc;
+}
+
+
+status_t Client::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ // these must be checked
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ const int self_pid = getpid();
+ if (CC_UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != 0)) {
+ // we're called from a different process, do the real check
+ if (!PermissionCache::checkCallingPermission(sAccessSurfaceFlinger))
+ {
+ ALOGE("Permission Denial: "
+ "can't openGlobalTransaction pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
+ }
+ }
+ return BnSurfaceComposerClient::onTransact(code, data, reply, flags);
+}
+
+
+sp<ISurface> Client::createSurface(
+ ISurfaceComposerClient::surface_data_t* params,
+ const String8& name,
+ DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
+ uint32_t flags)
+{
+ /*
+ * createSurface must be called from the GL thread so that it can
+ * have access to the GL context.
+ */
+
+ class MessageCreateSurface : public MessageBase {
+ sp<ISurface> result;
+ SurfaceFlinger* flinger;
+ ISurfaceComposerClient::surface_data_t* params;
+ Client* client;
+ const String8& name;
+ DisplayID display;
+ uint32_t w, h;
+ PixelFormat format;
+ uint32_t flags;
+ public:
+ MessageCreateSurface(SurfaceFlinger* flinger,
+ ISurfaceComposerClient::surface_data_t* params,
+ const String8& name, Client* client,
+ DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
+ uint32_t flags)
+ : flinger(flinger), params(params), client(client), name(name),
+ display(display), w(w), h(h), format(format), flags(flags)
+ {
+ }
+ sp<ISurface> getResult() const { return result; }
+ virtual bool handler() {
+ result = flinger->createSurface(params, name, client,
+ display, w, h, format, flags);
+ return true;
+ }
+ };
+
+ sp<MessageBase> msg = new MessageCreateSurface(mFlinger.get(),
+ params, name, this, display, w, h, format, flags);
+ mFlinger->postMessageSync(msg);
+ return static_cast<MessageCreateSurface*>( msg.get() )->getResult();
+}
+status_t Client::destroySurface(SurfaceID sid) {
+ return mFlinger->removeSurface(this, sid);
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h
new file mode 100644
index 0000000..9bfee72
--- /dev/null
+++ b/services/surfaceflinger/Client.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SF_CLIENT_H
+#define ANDROID_SF_CLIENT_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/Mutex.h>
+
+#include <gui/ISurfaceComposerClient.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class LayerBaseClient;
+class SurfaceFlinger;
+
+// ---------------------------------------------------------------------------
+
+class Client : public BnSurfaceComposerClient
+{
+public:
+ Client(const sp<SurfaceFlinger>& flinger);
+ ~Client();
+
+ status_t initCheck() const;
+
+ // protected by SurfaceFlinger::mStateLock
+ size_t attachLayer(const sp<LayerBaseClient>& layer);
+
+ void detachLayer(const LayerBaseClient* layer);
+
+ sp<LayerBaseClient> getLayerUser(int32_t i) const;
+
+private:
+ // ISurfaceComposerClient interface
+ virtual sp<ISurface> createSurface(
+ surface_data_t* params, const String8& name,
+ DisplayID display, uint32_t w, uint32_t h,PixelFormat format,
+ uint32_t flags);
+
+ virtual status_t destroySurface(SurfaceID surfaceId);
+
+ virtual status_t onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
+
+ // constant
+ sp<SurfaceFlinger> mFlinger;
+
+ // protected by mLock
+ DefaultKeyedVector< size_t, wp<LayerBaseClient> > mLayers;
+ size_t mNameGenerator;
+
+ // thread-safe
+ mutable Mutex mLock;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_SF_CLIENT_H
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index bb93215..e1c4f62 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -25,13 +25,13 @@
#include <utils/Log.h>
#include <ui/PixelFormat.h>
-#include <ui/FramebufferNativeWindow.h>
#include <GLES/gl.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include "DisplayHardware/DisplayHardware.h"
+#include "DisplayHardware/FramebufferSurface.h"
#include <hardware/gralloc.h>
@@ -148,7 +148,7 @@ static status_t selectConfigForPixelFormat(
void DisplayHardware::init(uint32_t dpy)
{
- mNativeWindow = new FramebufferNativeWindow();
+ mNativeWindow = new FramebufferSurface();
framebuffer_device_t const * fbDev = mNativeWindow->getDevice();
if (!fbDev) {
ALOGE("Display subsystem failed to initialize. check logs. exiting...");
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
index 0604031..f029a0a 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -35,7 +35,7 @@
namespace android {
-class FramebufferNativeWindow;
+class FramebufferSurface;
class DisplayHardware :
public DisplayHardwareBase,
@@ -144,7 +144,7 @@ private:
// protected by mLock
wp<VSyncHandler> mVSyncHandler;
- sp<FramebufferNativeWindow> mNativeWindow;
+ sp<FramebufferSurface> mNativeWindow;
};
}; // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
index d3a8bde..e161c44 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
@@ -30,91 +30,13 @@
// ----------------------------------------------------------------------------
namespace android {
-static char const * const kSleepFileName = "/sys/power/wait_for_fb_sleep";
-static char const * const kWakeFileName = "/sys/power/wait_for_fb_wake";
-
-// ----------------------------------------------------------------------------
-
-DisplayHardwareBase::DisplayEventThread::DisplayEventThread(
- const sp<SurfaceFlinger>& flinger)
- : Thread(false), mFlinger(flinger) {
-}
-
-DisplayHardwareBase::DisplayEventThread::~DisplayEventThread() {
-}
-
-status_t DisplayHardwareBase::DisplayEventThread::initCheck() const {
- return ((access(kSleepFileName, R_OK) == 0 &&
- access(kWakeFileName, R_OK) == 0)) ? NO_ERROR : NO_INIT;
-}
-
-bool DisplayHardwareBase::DisplayEventThread::threadLoop() {
-
- if (waitForFbSleep() == NO_ERROR) {
- sp<SurfaceFlinger> flinger = mFlinger.promote();
- ALOGD("About to give-up screen, flinger = %p", flinger.get());
- if (flinger != 0) {
- flinger->screenReleased();
- }
- if (waitForFbWake() == NO_ERROR) {
- ALOGD("Screen about to return, flinger = %p", flinger.get());
- if (flinger != 0) {
- flinger->screenAcquired();
- }
- return true;
- }
- }
-
- // error, exit the thread
- return false;
-}
-
-status_t DisplayHardwareBase::DisplayEventThread::waitForFbSleep() {
- int err = 0;
- char buf;
- int fd = open(kSleepFileName, O_RDONLY, 0);
- // if the file doesn't exist, the error will be caught in read() below
- do {
- err = read(fd, &buf, 1);
- } while (err < 0 && errno == EINTR);
- close(fd);
- ALOGE_IF(err<0, "*** ANDROID_WAIT_FOR_FB_SLEEP failed (%s)", strerror(errno));
- return err < 0 ? -errno : int(NO_ERROR);
-}
-
-status_t DisplayHardwareBase::DisplayEventThread::waitForFbWake() {
- int err = 0;
- char buf;
- int fd = open(kWakeFileName, O_RDONLY, 0);
- // if the file doesn't exist, the error will be caught in read() below
- do {
- err = read(fd, &buf, 1);
- } while (err < 0 && errno == EINTR);
- close(fd);
- ALOGE_IF(err<0, "*** ANDROID_WAIT_FOR_FB_WAKE failed (%s)", strerror(errno));
- return err < 0 ? -errno : int(NO_ERROR);
-}
-
-// ----------------------------------------------------------------------------
-
DisplayHardwareBase::DisplayHardwareBase(const sp<SurfaceFlinger>& flinger,
uint32_t displayIndex)
{
mScreenAcquired = true;
- mDisplayEventThread = new DisplayEventThread(flinger);
-}
-
-void DisplayHardwareBase::startSleepManagement() const {
- if (mDisplayEventThread->initCheck() == NO_ERROR) {
- mDisplayEventThread->run("DisplayEventThread", PRIORITY_URGENT_DISPLAY);
- } else {
- ALOGW("/sys/power/wait_for_fb_{wake|sleep} don't exist");
- }
}
DisplayHardwareBase::~DisplayHardwareBase() {
- // request exit
- mDisplayEventThread->requestExitAndWait();
}
bool DisplayHardwareBase::canDraw() const {
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
new file mode 100644
index 0000000..02d2b10
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -0,0 +1,188 @@
+/*
+ **
+ ** Copyright 2007 The Android Open Source Project
+ **
+ ** Licensed under the Apache License Version 2.0(the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ ** http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing software
+ ** distributed under the License is distributed on an "AS IS" BASIS
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <cutils/log.h>
+
+#include <utils/String8.h>
+
+#include <ui/Rect.h>
+
+#include <EGL/egl.h>
+
+#include <hardware/hardware.h>
+#include <gui/SurfaceTextureClient.h>
+#include <ui/GraphicBuffer.h>
+
+#include "DisplayHardware/FramebufferSurface.h"
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+
+/*
+ * This implements the (main) framebuffer management. This class is used
+ * mostly by SurfaceFlinger, but also by command line GL application.
+ *
+ */
+
+FramebufferSurface::FramebufferSurface()
+ : SurfaceTextureClient(),
+ fbDev(0), mCurrentBufferIndex(-1), mUpdateOnDemand(false)
+{
+ 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;
+
+ mUpdateOnDemand = (fbDev->setUpdateRect != 0);
+
+ const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags;
+ const_cast<float&>(ANativeWindow::xdpi) = fbDev->xdpi;
+ const_cast<float&>(ANativeWindow::ydpi) = fbDev->ydpi;
+ const_cast<int&>(ANativeWindow::minSwapInterval) = fbDev->minSwapInterval;
+ const_cast<int&>(ANativeWindow::maxSwapInterval) = fbDev->maxSwapInterval;
+ } else {
+ ALOGE("Couldn't get gralloc module");
+ }
+
+ class GraphicBufferAlloc : public BnGraphicBufferAlloc {
+ public:
+ GraphicBufferAlloc() { };
+ virtual ~GraphicBufferAlloc() { };
+ virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
+ PixelFormat format, uint32_t usage, status_t* error) {
+ sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage));
+ return graphicBuffer;
+ }
+ };
+
+ mBufferQueue = new BufferQueue(true, NUM_FRAME_BUFFERS, new GraphicBufferAlloc());
+ 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->setBufferCountServer(NUM_FRAME_BUFFERS);
+ setISurfaceTexture(mBufferQueue);
+}
+
+void FramebufferSurface::onFirstRef() {
+ class Listener : public BufferQueue::ConsumerListener {
+ const wp<FramebufferSurface> that;
+ virtual ~Listener() { }
+ virtual void onBuffersReleased() { }
+ void onFrameAvailable() {
+ sp<FramebufferSurface> self = that.promote();
+ if (self != NULL) {
+ BufferQueue::BufferItem item;
+ status_t err = self->mBufferQueue->acquireBuffer(&item);
+ if (err == 0) {
+ if (item.mGraphicBuffer != 0) {
+ self->mBuffers[item.mBuf] = item.mGraphicBuffer;
+ }
+ self->fbDev->post(self->fbDev, self->mBuffers[item.mBuf]->handle);
+ if (self->mCurrentBufferIndex >= 0) {
+ self->mBufferQueue->releaseBuffer(self->mCurrentBufferIndex,
+ EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE);
+ }
+ self->mCurrentBufferIndex = item.mBuf;
+ }
+ }
+ }
+ public:
+ Listener(const sp<FramebufferSurface>& that) : that(that) { }
+ };
+
+ mBufferQueue->setConsumerName(String8("FramebufferSurface"));
+ mBufferQueue->consumerConnect(new Listener(this));
+}
+
+FramebufferSurface::~FramebufferSurface() {
+ if (fbDev) {
+ framebuffer_close(fbDev);
+ }
+}
+
+status_t FramebufferSurface::setUpdateRectangle(const Rect& r)
+{
+ if (!mUpdateOnDemand) {
+ return INVALID_OPERATION;
+ }
+ return fbDev->setUpdateRect(fbDev, r.left, r.top, r.width(), r.height());
+}
+
+status_t FramebufferSurface::compositionComplete()
+{
+ if (fbDev->compositionComplete) {
+ return fbDev->compositionComplete(fbDev);
+ }
+ return INVALID_OPERATION;
+}
+
+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);
+ }
+}
+
+int FramebufferSurface::query(int what, int* value) const {
+ Mutex::Autolock _l(mLock);
+ framebuffer_device_t* fb = fbDev;
+ switch (what) {
+ case NATIVE_WINDOW_DEFAULT_WIDTH:
+ case NATIVE_WINDOW_WIDTH:
+ *value = fb->width;
+ return NO_ERROR;
+ case NATIVE_WINDOW_DEFAULT_HEIGHT:
+ case NATIVE_WINDOW_HEIGHT:
+ *value = fb->height;
+ return NO_ERROR;
+ case NATIVE_WINDOW_FORMAT:
+ *value = fb->format;
+ return NO_ERROR;
+ case NATIVE_WINDOW_CONCRETE_TYPE:
+ *value = NATIVE_WINDOW_FRAMEBUFFER;
+ return NO_ERROR;
+ case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
+ *value = 0;
+ return NO_ERROR;
+ case NATIVE_WINDOW_TRANSFORM_HINT:
+ *value = 0;
+ return NO_ERROR;
+ }
+ return SurfaceTextureClient::query(what, value);
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
new file mode 100644
index 0000000..5b4fd01
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SF_FRAMEBUFFER_SURFACE_H
+#define ANDROID_SF_FRAMEBUFFER_SURFACE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <EGL/egl.h>
+
+#include <gui/SurfaceTextureClient.h>
+
+#define NUM_FRAME_BUFFERS 2
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+class Rect;
+class String8;
+
+// ---------------------------------------------------------------------------
+
+class FramebufferSurface : public SurfaceTextureClient {
+public:
+ FramebufferSurface();
+
+ virtual void onFirstRef();
+
+ framebuffer_device_t const * getDevice() const { return fbDev; }
+
+ bool isUpdateOnDemand() const { return mUpdateOnDemand; }
+ status_t setUpdateRectangle(const Rect& updateRect);
+ status_t compositionComplete();
+
+ void dump(String8& result);
+
+private:
+ virtual ~FramebufferSurface(); // this class cannot be overloaded
+ virtual int query(int what, int* value) const;
+
+ framebuffer_device_t* fbDev;
+
+ sp<BufferQueue> mBufferQueue;
+ int mCurrentBufferIndex;
+ sp<GraphicBuffer> mBuffers[NUM_FRAME_BUFFERS];
+
+ mutable Mutex mLock;
+ bool mUpdateOnDemand;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_SF_FRAMEBUFFER_SURFACE_H
+
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 65763db..7c09ab2 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -16,6 +16,9 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+// Uncomment this to remove support for HWC_DEVICE_API_VERSION_0_3 and older
+// #define HWC_REMOVE_DEPRECATED_VERSIONS 1
+
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -41,6 +44,58 @@
#include "SurfaceFlinger.h"
namespace android {
+
+// ---------------------------------------------------------------------------
+// Support for HWC_DEVICE_API_VERSION_0_3 and older:
+// Since v0.3 is deprecated and support will be dropped soon, as much as
+// possible the code is written to target v1.0. When using a v0.3 HWC, we
+// allocate v0.3 structures, but assign them to v1.0 pointers. Fields that
+// exist in both versions are located at the same offset, so in most cases we
+// can just use the v1.0 pointer without branches or casts.
+
+#if HWC_REMOVE_DEPRECATED_VERSIONS
+// We need complete types with to satisfy semantic checks, even though the
+// code paths that use these won't get executed at runtime (and will likely be
+// dead-code-eliminated). When we remove the code to support v0.3 we can remove
+// these as well.
+typedef hwc_layer_1_t hwc_layer_t;
+typedef hwc_layer_list_1_t hwc_layer_list_t;
+typedef hwc_composer_device_1_t hwc_composer_device_t;
+#endif
+
+// This function assumes we've already rejected HWC's with lower-than-required
+// versions. Don't use it for the initial "does HWC meet requirements" check!
+static bool hwcHasVersion(const hwc_composer_device_1_t* hwc, uint32_t version) {
+ if (HWC_REMOVE_DEPRECATED_VERSIONS &&
+ version <= HWC_DEVICE_API_VERSION_1_0) {
+ return true;
+ } else {
+ return hwc->common.version >= version;
+ }
+}
+
+static size_t sizeofHwcLayerList(const hwc_composer_device_1_t* hwc,
+ size_t numLayers) {
+ if (hwcHasVersion(hwc, HWC_DEVICE_API_VERSION_1_0)) {
+ return sizeof(hwc_layer_list_1_t) + numLayers*sizeof(hwc_layer_1_t);
+ } else {
+ return sizeof(hwc_layer_list_t) + numLayers*sizeof(hwc_layer_t);
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+struct HWComposer::cb_context {
+ struct callbacks : public hwc_procs_t {
+ // these are here to facilitate the transition when adding
+ // new callbacks (an implementation can check for NULL before
+ // calling a new callback).
+ void (*zero[4])(void);
+ };
+ callbacks procs;
+ HWComposer* hwc;
+};
+
// ---------------------------------------------------------------------------
HWComposer::HWComposer(
@@ -51,6 +106,7 @@ HWComposer::HWComposer(
mModule(0), mHwc(0), mList(0), mCapacity(0),
mNumOVLayers(0), mNumFBLayers(0),
mDpy(EGL_NO_DISPLAY), mSur(EGL_NO_SURFACE),
+ mCBContext(new cb_context),
mEventHandler(handler),
mRefreshPeriod(refreshPeriod),
mVSyncCount(0), mDebugForceFakeVSync(false)
@@ -63,18 +119,28 @@ HWComposer::HWComposer(
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(mModule, &mHwc);
+ err = hwc_open_1(mModule, &mHwc);
ALOGE_IF(err, "%s device failed to initialize (%s)",
HWC_HARDWARE_COMPOSER, strerror(-err));
if (err == 0) {
+ if (HWC_REMOVE_DEPRECATED_VERSIONS &&
+ mHwc->common.version < HWC_DEVICE_API_VERSION_1_0) {
+ ALOGE("%s device version %#x too old, will not be used",
+ HWC_HARDWARE_COMPOSER, mHwc->common.version);
+ hwc_close_1(mHwc);
+ mHwc = NULL;
+ }
+ }
+
+ if (mHwc) {
if (mHwc->registerProcs) {
- mCBContext.hwc = this;
- mCBContext.procs.invalidate = &hook_invalidate;
- mCBContext.procs.vsync = &hook_vsync;
- mHwc->registerProcs(mHwc, &mCBContext.procs);
- memset(mCBContext.procs.zero, 0, sizeof(mCBContext.procs.zero));
+ mCBContext->hwc = this;
+ mCBContext->procs.invalidate = &hook_invalidate;
+ mCBContext->procs.vsync = &hook_vsync;
+ mHwc->registerProcs(mHwc, &mCBContext->procs);
+ memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero));
}
- if (mHwc->common.version >= HWC_DEVICE_API_VERSION_0_3) {
+ if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_0_3)) {
if (mDebugForceFakeVSync) {
// make sure to turn h/w vsync off in "fake vsync" mode
mHwc->methods->eventControl(mHwc, HWC_EVENT_VSYNC, 0);
@@ -100,8 +166,9 @@ HWComposer::~HWComposer() {
mVSyncThread->requestExitAndWait();
}
if (mHwc) {
- hwc_close(mHwc);
+ hwc_close_1(mHwc);
}
+ delete mCBContext;
}
status_t HWComposer::initCheck() const {
@@ -151,8 +218,8 @@ status_t HWComposer::createWorkList(size_t numLayers) {
if (mHwc) {
if (!mList || mCapacity < numLayers) {
free(mList);
- size_t size = sizeof(hwc_layer_list) + numLayers*sizeof(hwc_layer_t);
- mList = (hwc_layer_list_t*)malloc(size);
+ size_t size = sizeofHwcLayerList(mHwc, numLayers);
+ mList = (hwc_layer_list_1_t*)malloc(size);
mCapacity = numLayers;
}
mList->flags = HWC_GEOMETRY_CHANGED;
@@ -168,11 +235,19 @@ status_t HWComposer::prepare() const {
size_t numFBLayers = 0;
size_t count = mList->numHwLayers;
for (size_t i=0 ; i<count ; i++) {
- hwc_layer& l(mList->hwLayers[i]);
- if (l.flags & HWC_SKIP_LAYER) {
- l.compositionType = HWC_FRAMEBUFFER;
+ hwc_layer_1_t* l = NULL;
+ if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) {
+ l = &mList->hwLayers[i];
+ } else {
+ // mList really has hwc_layer_list_t memory layout
+ hwc_layer_list_t* list = (hwc_layer_list_t*)mList;
+ hwc_layer_t* layer = &list->hwLayers[i];
+ l = (hwc_layer_1_t*)layer;
}
- switch (l.compositionType) {
+ if (l->flags & HWC_SKIP_LAYER) {
+ l->compositionType = HWC_FRAMEBUFFER;
+ }
+ switch (l->compositionType) {
case HWC_OVERLAY:
numOVLayers++;
break;
@@ -207,7 +282,7 @@ status_t HWComposer::commit() const {
status_t HWComposer::release() const {
if (mHwc) {
- if (mHwc->common.version >= HWC_DEVICE_API_VERSION_0_3) {
+ if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_0_3)) {
mHwc->methods->eventControl(mHwc, HWC_EVENT_VSYNC, 0);
}
int err = mHwc->set(mHwc, NULL, NULL, NULL);
@@ -230,10 +305,195 @@ size_t HWComposer::getNumLayers() const {
return mList ? mList->numHwLayers : 0;
}
-hwc_layer_t* HWComposer::getLayers() const {
- return mList ? mList->hwLayers : 0;
+/*
+ * Helper template to implement a concrete HWCLayer
+ * This holds the pointer to the concrete hwc layer type
+ * and implements the "iterable" side of HWCLayer.
+ */
+template<typename CONCRETE, typename HWCTYPE>
+class Iterable : public HWComposer::HWCLayer {
+protected:
+ HWCTYPE* const mLayerList;
+ HWCTYPE* mCurrentLayer;
+ Iterable(HWCTYPE* layer) : mLayerList(layer), mCurrentLayer(layer) { }
+ inline HWCTYPE const * getLayer() const { return mCurrentLayer; }
+ inline HWCTYPE* getLayer() { return mCurrentLayer; }
+ virtual ~Iterable() { }
+private:
+ // returns a copy of ourselves
+ virtual HWComposer::HWCLayer* dup() {
+ return new CONCRETE( static_cast<const CONCRETE&>(*this) );
+ }
+ virtual status_t setLayer(size_t index) {
+ mCurrentLayer = &mLayerList[index];
+ return NO_ERROR;
+ }
+};
+
+// #if !HWC_REMOVE_DEPRECATED_VERSIONS
+/*
+ * Concrete implementation of HWCLayer for HWC_DEVICE_API_VERSION_0_3
+ * This implements the HWCLayer side of HWCIterableLayer.
+ */
+class HWCLayerVersion0 : public Iterable<HWCLayerVersion0, hwc_layer_t> {
+public:
+ HWCLayerVersion0(hwc_layer_t* layer)
+ : Iterable<HWCLayerVersion0, hwc_layer_t>(layer) { }
+
+ virtual int32_t getCompositionType() const {
+ return getLayer()->compositionType;
+ }
+ virtual uint32_t getHints() const {
+ return getLayer()->hints;
+ }
+ virtual int getAndResetReleaseFenceFd() {
+ // not supported on VERSION_03
+ return -1;
+ }
+
+ virtual void setDefaultState() {
+ getLayer()->compositionType = HWC_FRAMEBUFFER;
+ getLayer()->hints = 0;
+ getLayer()->flags = HWC_SKIP_LAYER;
+ getLayer()->transform = 0;
+ getLayer()->blending = HWC_BLENDING_NONE;
+ getLayer()->visibleRegionScreen.numRects = 0;
+ getLayer()->visibleRegionScreen.rects = NULL;
+ }
+ virtual void setSkip(bool skip) {
+ if (skip) {
+ getLayer()->flags |= HWC_SKIP_LAYER;
+ } else {
+ getLayer()->flags &= ~HWC_SKIP_LAYER;
+ }
+ }
+ virtual void setBlending(uint32_t blending) {
+ getLayer()->blending = blending;
+ }
+ virtual void setTransform(uint32_t transform) {
+ getLayer()->transform = transform;
+ }
+ virtual void setFrame(const Rect& frame) {
+ reinterpret_cast<Rect&>(getLayer()->displayFrame) = frame;
+ }
+ virtual void setCrop(const Rect& crop) {
+ reinterpret_cast<Rect&>(getLayer()->sourceCrop) = crop;
+ }
+ virtual void setVisibleRegionScreen(const Region& reg) {
+ getLayer()->visibleRegionScreen.rects =
+ reinterpret_cast<hwc_rect_t const *>(
+ reg.getArray(&getLayer()->visibleRegionScreen.numRects));
+ }
+ virtual void setBuffer(const sp<GraphicBuffer>& buffer) {
+ if (buffer == 0 || buffer->handle == 0) {
+ getLayer()->compositionType = HWC_FRAMEBUFFER;
+ getLayer()->flags |= HWC_SKIP_LAYER;
+ getLayer()->handle = 0;
+ } else {
+ getLayer()->handle = buffer->handle;
+ }
+ }
+};
+// #endif // !HWC_REMOVE_DEPRECATED_VERSIONS
+
+/*
+ * Concrete implementation of HWCLayer for HWC_DEVICE_API_VERSION_1_0.
+ * This implements the HWCLayer side of HWCIterableLayer.
+ */
+class HWCLayerVersion1 : public Iterable<HWCLayerVersion1, hwc_layer_1_t> {
+public:
+ HWCLayerVersion1(hwc_layer_1_t* layer)
+ : Iterable<HWCLayerVersion1, hwc_layer_1_t>(layer) { }
+
+ virtual int32_t getCompositionType() const {
+ return getLayer()->compositionType;
+ }
+ virtual uint32_t getHints() const {
+ return getLayer()->hints;
+ }
+ virtual int getAndResetReleaseFenceFd() {
+ int fd = getLayer()->releaseFenceFd;
+ getLayer()->releaseFenceFd = -1;
+ return fd;
+ }
+
+ virtual void setDefaultState() {
+ getLayer()->compositionType = HWC_FRAMEBUFFER;
+ getLayer()->hints = 0;
+ getLayer()->flags = HWC_SKIP_LAYER;
+ getLayer()->transform = 0;
+ getLayer()->blending = HWC_BLENDING_NONE;
+ getLayer()->visibleRegionScreen.numRects = 0;
+ getLayer()->visibleRegionScreen.rects = NULL;
+ getLayer()->acquireFenceFd = -1;
+ getLayer()->releaseFenceFd = -1;
+ }
+ virtual void setSkip(bool skip) {
+ if (skip) {
+ getLayer()->flags |= HWC_SKIP_LAYER;
+ } else {
+ getLayer()->flags &= ~HWC_SKIP_LAYER;
+ }
+ }
+ virtual void setBlending(uint32_t blending) {
+ getLayer()->blending = blending;
+ }
+ virtual void setTransform(uint32_t transform) {
+ getLayer()->transform = transform;
+ }
+ virtual void setFrame(const Rect& frame) {
+ reinterpret_cast<Rect&>(getLayer()->displayFrame) = frame;
+ }
+ virtual void setCrop(const Rect& crop) {
+ reinterpret_cast<Rect&>(getLayer()->sourceCrop) = crop;
+ }
+ virtual void setVisibleRegionScreen(const Region& reg) {
+ getLayer()->visibleRegionScreen.rects =
+ reinterpret_cast<hwc_rect_t const *>(
+ reg.getArray(&getLayer()->visibleRegionScreen.numRects));
+ }
+ virtual void setBuffer(const sp<GraphicBuffer>& buffer) {
+ if (buffer == 0 || buffer->handle == 0) {
+ getLayer()->compositionType = HWC_FRAMEBUFFER;
+ getLayer()->flags |= HWC_SKIP_LAYER;
+ getLayer()->handle = 0;
+ } else {
+ getLayer()->handle = buffer->handle;
+ }
+ }
+};
+
+/*
+ * returns an iterator initialized at a given index in the layer list
+ */
+HWComposer::LayerListIterator HWComposer::getLayerIterator(size_t index) {
+ if (!mList || index > mList->numHwLayers) {
+ return LayerListIterator();
+ }
+ if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) {
+ return LayerListIterator(new HWCLayerVersion1(mList->hwLayers), index);
+ } else {
+ hwc_layer_list_t* list0 = (hwc_layer_list_t*)mList;
+ return LayerListIterator(new HWCLayerVersion0(list0->hwLayers), index);
+ }
}
+/*
+ * returns an iterator on the beginning of the layer list
+ */
+HWComposer::LayerListIterator HWComposer::begin() {
+ return getLayerIterator(0);
+}
+
+/*
+ * returns an iterator on the end of the layer list
+ */
+HWComposer::LayerListIterator HWComposer::end() {
+ return getLayerIterator(getNumLayers());
+}
+
+
+
void HWComposer::dump(String8& result, char* buffer, size_t SIZE,
const Vector< sp<LayerBase> >& visibleLayersSortedByZ) const {
if (mHwc && mList) {
@@ -247,7 +507,14 @@ void HWComposer::dump(String8& result, char* buffer, size_t SIZE,
"----------+----------+----------+----------+----+-------+----------+---------------------------+--------------------------------\n");
// " ________ | ________ | ________ | ________ | __ | _____ | ________ | [_____,_____,_____,_____] | [_____,_____,_____,_____]
for (size_t i=0 ; i<mList->numHwLayers ; i++) {
- const hwc_layer_t& l(mList->hwLayers[i]);
+ hwc_layer_1_t l;
+ if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) {
+ l = mList->hwLayers[i];
+ } else {
+ hwc_layer_list_t* list0 = (hwc_layer_list_t*)mList;
+ *(hwc_layer_t*)&l = list0->hwLayers[i];
+ l.acquireFenceFd = l.releaseFenceFd = -1;
+ }
const sp<LayerBase> layer(visibleLayersSortedByZ[i]);
int32_t format = -1;
if (layer->getLayer() != NULL) {
@@ -265,7 +532,7 @@ void HWComposer::dump(String8& result, char* buffer, size_t SIZE,
layer->getName().string());
}
}
- if (mHwc && mHwc->common.version >= HWC_DEVICE_API_VERSION_0_1 && mHwc->dump) {
+ if (mHwc && hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_0_1) && mHwc->dump) {
mHwc->dump(mHwc, buffer, SIZE);
result.append(buffer);
}
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index aada3cd..cb4c2db 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -22,7 +22,7 @@
#include <EGL/egl.h>
-#include <hardware/hwcomposer.h>
+#include <hardware/hwcomposer_defs.h>
#include <utils/StrongPointer.h>
#include <utils/Vector.h>
@@ -31,12 +31,17 @@ extern "C" int clock_nanosleep(clockid_t clock_id, int flags,
const struct timespec *request,
struct timespec *remain);
+struct hwc_composer_device_1;
+struct hwc_layer_list_1;
+struct hwc_procs;
+
namespace android {
// ---------------------------------------------------------------------------
class String8;
class SurfaceFlinger;
class LayerBase;
+class GraphicBuffer;
class HWComposer
{
@@ -57,9 +62,6 @@ public:
// tells the HAL what the framebuffer is
void setFrameBuffer(EGLDisplay dpy, EGLSurface sur);
- // create a work list for numLayers layer. sets HWC_GEOMETRY_CHANGED.
- status_t createWorkList(size_t numLayers);
-
// Asks the HAL what it can do
status_t prepare() const;
@@ -72,14 +74,110 @@ public:
// release hardware resources
status_t release() const;
+ // create a work list for numLayers layer. sets HWC_GEOMETRY_CHANGED.
+ status_t createWorkList(size_t numLayers);
+
// get the layer array created by createWorkList()
size_t getNumLayers() const;
- hwc_layer_t* getLayers() const;
// get number of layers of the given type as updated in prepare().
// type is HWC_OVERLAY or HWC_FRAMEBUFFER
size_t getLayerCount(int type) const;
+ // needed forward declarations
+ class LayerListIterator;
+
+ /*
+ * Interface to hardware composer's layers functionality.
+ * This abstracts the HAL interface to layers which can evolve in
+ * incompatible ways from one release to another.
+ * The idea is that we could extend this interface as we add
+ * features to h/w composer.
+ */
+ class HWCLayerInterface {
+ protected:
+ virtual ~HWCLayerInterface() { }
+ public:
+ virtual int32_t getCompositionType() const = 0;
+ virtual uint32_t getHints() const = 0;
+ virtual int getAndResetReleaseFenceFd() = 0;
+ virtual void setDefaultState() = 0;
+ virtual void setSkip(bool skip) = 0;
+ virtual void setBlending(uint32_t blending) = 0;
+ virtual void setTransform(uint32_t transform) = 0;
+ virtual void setFrame(const Rect& frame) = 0;
+ virtual void setCrop(const Rect& crop) = 0;
+ virtual void setVisibleRegionScreen(const Region& reg) = 0;
+ virtual void setBuffer(const sp<GraphicBuffer>& buffer) = 0;
+ };
+
+ /*
+ * Interface used to implement an iterator to a list
+ * of HWCLayer.
+ */
+ class HWCLayer : public HWCLayerInterface {
+ friend class LayerListIterator;
+ // select the layer at the given index
+ virtual status_t setLayer(size_t index) = 0;
+ virtual HWCLayer* dup() = 0;
+ static HWCLayer* copy(HWCLayer *rhs) {
+ return rhs ? rhs->dup() : NULL;
+ }
+ protected:
+ virtual ~HWCLayer() { }
+ };
+
+ /*
+ * Iterator through a HWCLayer list.
+ * This behaves more or less like a forward iterator.
+ */
+ class LayerListIterator {
+ friend struct HWComposer;
+ HWCLayer* const mLayerList;
+ size_t mIndex;
+
+ LayerListIterator() : mLayerList(NULL), mIndex(0) { }
+
+ LayerListIterator(HWCLayer* layer, size_t index)
+ : mLayerList(layer), mIndex(index) { }
+
+ // we don't allow assignment, because we don't need it for now
+ LayerListIterator& operator = (const LayerListIterator& rhs);
+
+ public:
+ // copy operators
+ LayerListIterator(const LayerListIterator& rhs)
+ : mLayerList(HWCLayer::copy(rhs.mLayerList)), mIndex(rhs.mIndex) {
+ }
+
+ ~LayerListIterator() { delete mLayerList; }
+
+ // pre-increment
+ LayerListIterator& operator++() {
+ mLayerList->setLayer(++mIndex);
+ return *this;
+ }
+
+ // dereference
+ HWCLayerInterface& operator * () { return *mLayerList; }
+ HWCLayerInterface* operator -> () { return mLayerList; }
+
+ // comparison
+ bool operator == (const LayerListIterator& rhs) const {
+ return mIndex == rhs.mIndex;
+ }
+ bool operator != (const LayerListIterator& rhs) const {
+ return !operator==(rhs);
+ }
+ };
+
+ // Returns an iterator to the beginning of the layer list
+ LayerListIterator begin();
+
+ // Returns an iterator to the end of the layer list
+ LayerListIterator end();
+
+
// Events handling ---------------------------------------------------------
enum {
@@ -111,18 +209,9 @@ public:
const Vector< sp<LayerBase> >& visibleLayersSortedByZ) const;
private:
+ LayerListIterator getLayerIterator(size_t index);
- struct callbacks : public hwc_procs_t {
- // these are here to facilitate the transition when adding
- // new callbacks (an implementation can check for NULL before
- // calling a new callback).
- void (*zero[4])(void);
- };
-
- struct cb_context {
- callbacks procs;
- HWComposer* hwc;
- };
+ struct cb_context;
static void hook_invalidate(struct hwc_procs* procs);
static void hook_vsync(struct hwc_procs* procs, int dpy, int64_t timestamp);
@@ -130,24 +219,23 @@ private:
inline void invalidate();
inline void vsync(int dpy, int64_t timestamp);
- sp<SurfaceFlinger> mFlinger;
- hw_module_t const* mModule;
- hwc_composer_device_t* mHwc;
- hwc_layer_list_t* mList;
- size_t mCapacity;
- mutable size_t mNumOVLayers;
- mutable size_t mNumFBLayers;
- hwc_display_t mDpy;
- hwc_surface_t mSur;
- cb_context mCBContext;
- EventHandler& mEventHandler;
- nsecs_t mRefreshPeriod;
- size_t mVSyncCount;
- sp<VSyncThread> mVSyncThread;
- bool mDebugForceFakeVSync;
+ sp<SurfaceFlinger> mFlinger;
+ hw_module_t const* mModule;
+ struct hwc_composer_device_1* mHwc;
+ struct hwc_layer_list_1* mList;
+ size_t mCapacity;
+ mutable size_t mNumOVLayers;
+ mutable size_t mNumFBLayers;
+ EGLDisplay mDpy;
+ EGLSurface mSur;
+ cb_context* mCBContext;
+ EventHandler& mEventHandler;
+ nsecs_t mRefreshPeriod;
+ size_t mVSyncCount;
+ sp<VSyncThread> mVSyncThread;
+ bool mDebugForceFakeVSync;
};
-
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 4062340..64e4b5f 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -71,7 +71,11 @@ Layer::Layer(SurfaceFlinger* flinger,
glGenTextures(1, &mTextureName);
}
-void Layer::onLayerDisplayed() {
+void Layer::onLayerDisplayed(HWComposer::HWCLayerInterface* layer) {
+ if (layer) {
+ mSurfaceTexture->setReleaseFence(layer->getAndResetReleaseFenceFd());
+ }
+
if (mFrameLatencyNeeded) {
const DisplayHardware& hw(graphicPlane(0).displayHardware());
mFrameStats[mFrameLatencyOffset].timestamp = mSurfaceTexture->getTimestamp();
@@ -259,16 +263,17 @@ Rect Layer::computeBufferCrop() const {
return crop;
}
-void Layer::setGeometry(hwc_layer_t* hwcl)
+void Layer::setGeometry(HWComposer::HWCLayerInterface& layer)
{
- LayerBaseClient::setGeometry(hwcl);
+ LayerBaseClient::setGeometry(layer);
- hwcl->flags &= ~HWC_SKIP_LAYER;
+ // enable this layer
+ layer.setSkip(false);
// we can't do alpha-fade with the hwc HAL
const State& s(drawingState());
if (s.alpha < 0xFF) {
- hwcl->flags = HWC_SKIP_LAYER;
+ layer.setSkip(true);
}
/*
@@ -288,29 +293,18 @@ void Layer::setGeometry(hwc_layer_t* hwcl)
// we can only handle simple transformation
if (finalTransform & Transform::ROT_INVALID) {
- hwcl->flags = HWC_SKIP_LAYER;
+ layer.setSkip(true);
} else {
- hwcl->transform = finalTransform;
+ layer.setTransform(finalTransform);
}
-
- Rect crop = computeBufferCrop();
- hwcl->sourceCrop.left = crop.left;
- hwcl->sourceCrop.top = crop.top;
- hwcl->sourceCrop.right = crop.right;
- hwcl->sourceCrop.bottom = crop.bottom;
+ layer.setCrop(computeBufferCrop());
}
-void Layer::setPerFrameData(hwc_layer_t* hwcl) {
+void Layer::setPerFrameData(HWComposer::HWCLayerInterface& layer) {
const sp<GraphicBuffer>& buffer(mActiveBuffer);
- if (buffer == NULL) {
- // this can happen if the client never drew into this layer yet,
- // or if we ran out of memory. In that case, don't let
- // HWC handle it.
- hwcl->flags |= HWC_SKIP_LAYER;
- hwcl->handle = NULL;
- } else {
- hwcl->handle = buffer->handle;
- }
+ // NOTE: buffer can be NULL if the client never drew into this
+ // layer yet, or if we ran out of memory
+ layer.setBuffer(buffer);
}
void Layer::onDraw(const Region& clip) const
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 393599f..32456f4 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -64,8 +64,8 @@ public:
bool isFixedSize() const;
// LayerBase interface
- virtual void setGeometry(hwc_layer_t* hwcl);
- virtual void setPerFrameData(hwc_layer_t* hwcl);
+ virtual void setGeometry(HWComposer::HWCLayerInterface& layer);
+ virtual void setPerFrameData(HWComposer::HWCLayerInterface& layer);
virtual void onDraw(const Region& clip) const;
virtual uint32_t doTransaction(uint32_t transactionFlags);
virtual void lockPageFlip(bool& recomputeVisibleRegions);
@@ -82,7 +82,7 @@ public:
// LayerBaseClient interface
virtual wp<IBinder> getSurfaceTextureBinder() const;
- virtual void onLayerDisplayed();
+ virtual void onLayerDisplayed(HWComposer::HWCLayerInterface* layer);
virtual bool onPreComposition();
// only for debugging
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index 16bac8f..893dcb9 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -29,6 +29,7 @@
#include <hardware/hardware.h>
#include "clz.h"
+#include "Client.h"
#include "LayerBase.h"
#include "SurfaceFlinger.h"
#include "DisplayHardware/DisplayHardware.h"
@@ -281,48 +282,34 @@ void LayerBase::unlockPageFlip(
const Transform& planeTransform, Region& outDirtyRegion) {
}
-void LayerBase::setGeometry(hwc_layer_t* hwcl)
+void LayerBase::setGeometry(HWComposer::HWCLayerInterface& layer)
{
- hwcl->compositionType = HWC_FRAMEBUFFER;
- hwcl->hints = 0;
- hwcl->flags = HWC_SKIP_LAYER;
- hwcl->transform = 0;
- hwcl->blending = HWC_BLENDING_NONE;
+ layer.setDefaultState();
// this gives us only the "orientation" component of the transform
const State& s(drawingState());
const uint32_t finalTransform = s.transform.getOrientation();
// we can only handle simple transformation
if (finalTransform & Transform::ROT_INVALID) {
- hwcl->flags = HWC_SKIP_LAYER;
+ layer.setTransform(0);
} else {
- hwcl->transform = finalTransform;
+ layer.setTransform(finalTransform);
}
if (!isOpaque()) {
- hwcl->blending = mPremultipliedAlpha ?
- HWC_BLENDING_PREMULT : HWC_BLENDING_COVERAGE;
+ layer.setBlending(mPremultipliedAlpha ?
+ HWC_BLENDING_PREMULT :
+ HWC_BLENDING_COVERAGE);
}
// scaling is already applied in mTransformedBounds
- hwcl->displayFrame.left = mTransformedBounds.left;
- hwcl->displayFrame.top = mTransformedBounds.top;
- hwcl->displayFrame.right = mTransformedBounds.right;
- hwcl->displayFrame.bottom = mTransformedBounds.bottom;
- hwcl->visibleRegionScreen.rects =
- reinterpret_cast<hwc_rect_t const *>(
- visibleRegionScreen.getArray(
- &hwcl->visibleRegionScreen.numRects));
-
- hwcl->sourceCrop.left = 0;
- hwcl->sourceCrop.top = 0;
- hwcl->sourceCrop.right = mTransformedBounds.width();
- hwcl->sourceCrop.bottom = mTransformedBounds.height();
-}
-
-void LayerBase::setPerFrameData(hwc_layer_t* hwcl) {
- hwcl->compositionType = HWC_FRAMEBUFFER;
- hwcl->handle = NULL;
+ layer.setFrame(mTransformedBounds);
+ layer.setVisibleRegionScreen(visibleRegionScreen);
+ layer.setCrop(mTransformedBounds.getBounds());
+}
+
+void LayerBase::setPerFrameData(HWComposer::HWCLayerInterface& layer) {
+ layer.setBuffer(0);
}
void LayerBase::setFiltering(bool filtering)
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index c547a40..698cdb8 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -32,8 +32,6 @@
#include <private/gui/LayerState.h>
-#include <hardware/hwcomposer.h>
-
#include "DisplayHardware/DisplayHardware.h"
#include "Transform.h"
@@ -116,8 +114,8 @@ public:
virtual const char* getTypeId() const { return "LayerBase"; }
- virtual void setGeometry(hwc_layer_t* hwcl);
- virtual void setPerFrameData(hwc_layer_t* hwcl);
+ virtual void setGeometry(HWComposer::HWCLayerInterface& layer);
+ virtual void setPerFrameData(HWComposer::HWCLayerInterface& layer);
/**
@@ -212,7 +210,7 @@ public:
/** called after page-flip
*/
- virtual void onLayerDisplayed() { }
+ virtual void onLayerDisplayed(HWComposer::HWCLayerInterface* layer) { }
/** called before composition.
* returns true if the layer has pending updates.
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 51fcce4..981d694 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -50,6 +50,7 @@
#include "clz.h"
#include "DdmConnection.h"
+#include "Client.h"
#include "EventThread.h"
#include "GLExtensions.h"
#include "Layer.h"
@@ -117,6 +118,8 @@ void SurfaceFlinger::init()
if (mDebugDDMS) {
DdmConnection::start(getServiceName());
}
+#else
+#warning "DDMS_DEBUGGING disabled"
#endif
ALOGI_IF(mDebugRegion, "showupdates enabled");
@@ -299,7 +302,6 @@ status_t SurfaceFlinger::readyToRun()
// start the EventThread
mEventThread = new EventThread(this);
mEventQueue.setEventThread(mEventThread);
- hw.startSleepManagement();
/*
* We're now ready to accept clients...
@@ -470,8 +472,17 @@ void SurfaceFlinger::postFramebuffer()
hw.flip(mSwapRegion);
size_t numLayers = mVisibleLayersSortedByZ.size();
- for (size_t i = 0; i < numLayers; i++) {
- mVisibleLayersSortedByZ[i]->onLayerDisplayed();
+ HWComposer& hwc(graphicPlane(0).displayHardware().getHwComposer());
+ if (hwc.initCheck() == NO_ERROR) {
+ HWComposer::LayerListIterator cur = hwc.begin();
+ const HWComposer::LayerListIterator end = hwc.end();
+ for (size_t i = 0; cur != end && i < numLayers; ++i, ++cur) {
+ mVisibleLayersSortedByZ[i]->onLayerDisplayed(&*cur);
+ }
+ } else {
+ for (size_t i = 0; i < numLayers; i++) {
+ mVisibleLayersSortedByZ[i]->onLayerDisplayed(NULL);
+ }
}
mLastSwapBufferTime = systemTime() - now;
@@ -809,12 +820,13 @@ void SurfaceFlinger::handleWorkList()
const Vector< sp<LayerBase> >& currentLayers(mVisibleLayersSortedByZ);
const size_t count = currentLayers.size();
hwc.createWorkList(count);
- hwc_layer_t* const cur(hwc.getLayers());
- for (size_t i=0 ; cur && i<count ; i++) {
- currentLayers[i]->setGeometry(&cur[i]);
+
+ HWComposer::LayerListIterator cur = hwc.begin();
+ const HWComposer::LayerListIterator end = hwc.end();
+ for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
+ currentLayers[i]->setGeometry(*cur);
if (mDebugDisableHWC || mDebugRegion) {
- cur[i].compositionType = HWC_FRAMEBUFFER;
- cur[i].flags |= HWC_SKIP_LAYER;
+ cur->setSkip(true);
}
}
}
@@ -868,8 +880,10 @@ void SurfaceFlinger::setupHardwareComposer()
{
const DisplayHardware& hw(graphicPlane(0).displayHardware());
HWComposer& hwc(hw.getHwComposer());
- hwc_layer_t* const cur(hwc.getLayers());
- if (!cur) {
+
+ HWComposer::LayerListIterator cur = hwc.begin();
+ const HWComposer::LayerListIterator end = hwc.end();
+ if (cur == end) {
return;
}
@@ -889,9 +903,9 @@ void SurfaceFlinger::setupHardwareComposer()
* update the per-frame h/w composer data for each layer
* and build the transparent region of the FB
*/
- for (size_t i=0 ; i<count ; i++) {
+ for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
const sp<LayerBase>& layer(layers[i]);
- layer->setPerFrameData(&cur[i]);
+ layer->setPerFrameData(*cur);
}
status_t err = hwc.prepare();
ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
@@ -901,10 +915,11 @@ void SurfaceFlinger::composeSurfaces(const Region& dirty)
{
const DisplayHardware& hw(graphicPlane(0).displayHardware());
HWComposer& hwc(hw.getHwComposer());
- hwc_layer_t* const cur(hwc.getLayers());
+ HWComposer::LayerListIterator cur = hwc.begin();
+ const HWComposer::LayerListIterator end = hwc.end();
const size_t fbLayerCount = hwc.getLayerCount(HWC_FRAMEBUFFER);
- if (!cur || fbLayerCount) {
+ if (cur==end || fbLayerCount) {
// Never touch the framebuffer if we don't have any framebuffer layers
if (hwc.getLayerCount(HWC_OVERLAY)) {
@@ -929,13 +944,12 @@ void SurfaceFlinger::composeSurfaces(const Region& dirty)
const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
const size_t count = layers.size();
-
- for (size_t i=0 ; i<count ; i++) {
+ for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
const sp<LayerBase>& layer(layers[i]);
const Region clip(dirty.intersect(layer->visibleRegionScreen));
if (!clip.isEmpty()) {
- if (cur && (cur[i].compositionType == HWC_OVERLAY)) {
- if (i && (cur[i].hints & HWC_HINT_CLEAR_FB)
+ if (cur->getCompositionType() == HWC_OVERLAY) {
+ if (i && (cur->getHints() & HWC_HINT_CLEAR_FB)
&& layer->isOpaque()) {
// never clear the very first layer since we're
// guaranteed the FB is already cleared
@@ -1371,6 +1385,7 @@ uint32_t SurfaceFlinger::setClientStateLocked(
// ---------------------------------------------------------------------------
void SurfaceFlinger::onScreenAcquired() {
+ ALOGD("Screen about to return, flinger = %p", this);
const DisplayHardware& hw(graphicPlane(0).displayHardware());
hw.acquireScreen();
mEventThread->onScreenAcquired();
@@ -1382,6 +1397,7 @@ void SurfaceFlinger::onScreenAcquired() {
}
void SurfaceFlinger::onScreenReleased() {
+ ALOGD("About to give-up screen, flinger = %p", this);
const DisplayHardware& hw(graphicPlane(0).displayHardware());
if (hw.isScreenAcquired()) {
mEventThread->onScreenReleased();
@@ -1390,7 +1406,7 @@ void SurfaceFlinger::onScreenReleased() {
}
}
-void SurfaceFlinger::screenAcquired() {
+void SurfaceFlinger::unblank() {
class MessageScreenAcquired : public MessageBase {
SurfaceFlinger* flinger;
public:
@@ -1404,7 +1420,7 @@ void SurfaceFlinger::screenAcquired() {
postMessageSync(msg);
}
-void SurfaceFlinger::screenReleased() {
+void SurfaceFlinger::blank() {
class MessageScreenReleased : public MessageBase {
SurfaceFlinger* flinger;
public:
@@ -1662,6 +1678,8 @@ status_t SurfaceFlinger::onTransact(
case BOOT_FINISHED:
case TURN_ELECTRON_BEAM_OFF:
case TURN_ELECTRON_BEAM_ON:
+ case BLANK:
+ case UNBLANK:
{
// codes that require permission check
IPCThreadState* ipc = IPCThreadState::self();
@@ -2511,130 +2529,6 @@ sp<Layer> SurfaceFlinger::getLayer(const sp<ISurface>& sur) const
// ---------------------------------------------------------------------------
-Client::Client(const sp<SurfaceFlinger>& flinger)
- : mFlinger(flinger), mNameGenerator(1)
-{
-}
-
-Client::~Client()
-{
- const size_t count = mLayers.size();
- for (size_t i=0 ; i<count ; i++) {
- sp<LayerBaseClient> layer(mLayers.valueAt(i).promote());
- if (layer != 0) {
- mFlinger->removeLayer(layer);
- }
- }
-}
-
-status_t Client::initCheck() const {
- return NO_ERROR;
-}
-
-size_t Client::attachLayer(const sp<LayerBaseClient>& layer)
-{
- Mutex::Autolock _l(mLock);
- size_t name = mNameGenerator++;
- mLayers.add(name, layer);
- return name;
-}
-
-void Client::detachLayer(const LayerBaseClient* layer)
-{
- Mutex::Autolock _l(mLock);
- // we do a linear search here, because this doesn't happen often
- const size_t count = mLayers.size();
- for (size_t i=0 ; i<count ; i++) {
- if (mLayers.valueAt(i) == layer) {
- mLayers.removeItemsAt(i, 1);
- break;
- }
- }
-}
-sp<LayerBaseClient> Client::getLayerUser(int32_t i) const
-{
- Mutex::Autolock _l(mLock);
- sp<LayerBaseClient> lbc;
- wp<LayerBaseClient> layer(mLayers.valueFor(i));
- if (layer != 0) {
- lbc = layer.promote();
- ALOGE_IF(lbc==0, "getLayerUser(name=%d) is dead", int(i));
- }
- return lbc;
-}
-
-
-status_t Client::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- // these must be checked
- IPCThreadState* ipc = IPCThreadState::self();
- const int pid = ipc->getCallingPid();
- const int uid = ipc->getCallingUid();
- const int self_pid = getpid();
- if (CC_UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != 0)) {
- // we're called from a different process, do the real check
- if (!PermissionCache::checkCallingPermission(sAccessSurfaceFlinger))
- {
- ALOGE("Permission Denial: "
- "can't openGlobalTransaction pid=%d, uid=%d", pid, uid);
- return PERMISSION_DENIED;
- }
- }
- return BnSurfaceComposerClient::onTransact(code, data, reply, flags);
-}
-
-
-sp<ISurface> Client::createSurface(
- ISurfaceComposerClient::surface_data_t* params,
- const String8& name,
- DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
- uint32_t flags)
-{
- /*
- * createSurface must be called from the GL thread so that it can
- * have access to the GL context.
- */
-
- class MessageCreateSurface : public MessageBase {
- sp<ISurface> result;
- SurfaceFlinger* flinger;
- ISurfaceComposerClient::surface_data_t* params;
- Client* client;
- const String8& name;
- DisplayID display;
- uint32_t w, h;
- PixelFormat format;
- uint32_t flags;
- public:
- MessageCreateSurface(SurfaceFlinger* flinger,
- ISurfaceComposerClient::surface_data_t* params,
- const String8& name, Client* client,
- DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
- uint32_t flags)
- : flinger(flinger), params(params), client(client), name(name),
- display(display), w(w), h(h), format(format), flags(flags)
- {
- }
- sp<ISurface> getResult() const { return result; }
- virtual bool handler() {
- result = flinger->createSurface(params, name, client,
- display, w, h, format, flags);
- return true;
- }
- };
-
- sp<MessageBase> msg = new MessageCreateSurface(mFlinger.get(),
- params, name, this, display, w, h, format, flags);
- mFlinger->postMessageSync(msg);
- return static_cast<MessageCreateSurface*>( msg.get() )->getResult();
-}
-status_t Client::destroySurface(SurfaceID sid) {
- return mFlinger->removeSurface(this, sid);
-}
-
-// ---------------------------------------------------------------------------
-
GraphicBufferAlloc::GraphicBufferAlloc() {}
GraphicBufferAlloc::~GraphicBufferAlloc() {}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index b20973b..c3efdbc 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -57,40 +57,6 @@ struct surface_flinger_cblk_t;
// ---------------------------------------------------------------------------
-class Client : public BnSurfaceComposerClient
-{
-public:
- Client(const sp<SurfaceFlinger>& flinger);
- ~Client();
-
- status_t initCheck() const;
-
- // protected by SurfaceFlinger::mStateLock
- size_t attachLayer(const sp<LayerBaseClient>& layer);
- void detachLayer(const LayerBaseClient* layer);
- sp<LayerBaseClient> getLayerUser(int32_t i) const;
-
-private:
- // ISurfaceComposerClient interface
- virtual sp<ISurface> createSurface(
- surface_data_t* params, const String8& name,
- DisplayID display, uint32_t w, uint32_t h,PixelFormat format,
- uint32_t flags);
- virtual status_t destroySurface(SurfaceID surfaceId);
- virtual status_t onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
-
- // constant
- sp<SurfaceFlinger> mFlinger;
-
- // protected by mLock
- DefaultKeyedVector< size_t, wp<LayerBaseClient> > mLayers;
- size_t mNameGenerator;
-
- // thread-safe
- mutable Mutex mLock;
-};
-
class GraphicBufferAlloc : public BnGraphicBufferAlloc
{
public:
@@ -182,11 +148,10 @@ public:
virtual status_t turnElectronBeamOff(int32_t mode);
virtual status_t turnElectronBeamOn(int32_t mode);
-
// called when screen needs to turn off
- void screenReleased();
+ virtual void blank();
// called when screen is turning back on
- void screenAcquired();
+ virtual void unblank();
// called on the main thread in response to screenReleased()
void onScreenReleased();