diff options
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(); |