diff options
Diffstat (limited to 'libs')
35 files changed, 1774 insertions, 1361 deletions
diff --git a/libs/binder/Android.mk b/libs/binder/Android.mk index f9d9f25..3a12e96 100644 --- a/libs/binder/Android.mk +++ b/libs/binder/Android.mk @@ -27,7 +27,7 @@ sources := \ MemoryHeapBase.cpp \ MemoryHeapPmem.cpp \ Parcel.cpp \ - Permission.cpp \ + PermissionCache.cpp \ ProcessState.cpp \ Static.cpp diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp index bc8c412..1ace8f8 100644 --- a/libs/binder/IMemory.cpp +++ b/libs/binder/IMemory.cpp @@ -42,11 +42,11 @@ class HeapCache : public IBinder::DeathRecipient public: HeapCache(); virtual ~HeapCache(); - + virtual void binderDied(const wp<IBinder>& who); - sp<IMemoryHeap> find_heap(const sp<IBinder>& binder); - void free_heap(const sp<IBinder>& binder); + sp<IMemoryHeap> find_heap(const sp<IBinder>& binder); + void free_heap(const sp<IBinder>& binder); sp<IMemoryHeap> get_heap(const sp<IBinder>& binder); void dump_heaps(); @@ -57,7 +57,7 @@ private: int32_t count; }; - void free_heap(const wp<IBinder>& binder); + void free_heap(const wp<IBinder>& binder); Mutex mHeapCacheLock; KeyedVector< wp<IBinder>, heap_info_t > mHeapCache; @@ -81,11 +81,12 @@ public: virtual void* getBase() const; virtual size_t getSize() const; virtual uint32_t getFlags() const; + virtual uint32_t getOffset() const; private: friend class IMemory; friend class HeapCache; - + // for debugging in this module static inline sp<IMemoryHeap> find_heap(const sp<IBinder>& binder) { return gHeapCache->find_heap(binder); @@ -97,7 +98,7 @@ private: return gHeapCache->get_heap(binder); } static inline void dump_heaps() { - gHeapCache->dump_heaps(); + gHeapCache->dump_heaps(); } void assertMapped() const; @@ -107,6 +108,7 @@ private: mutable void* mBase; mutable size_t mSize; mutable uint32_t mFlags; + mutable uint32_t mOffset; mutable bool mRealHeap; mutable Mutex mLock; }; @@ -123,7 +125,7 @@ public: BpMemory(const sp<IBinder>& impl); virtual ~BpMemory(); virtual sp<IMemoryHeap> getMemory(ssize_t* offset=0, size_t* size=0) const; - + private: mutable sp<IMemoryHeap> mHeap; mutable ssize_t mOffset; @@ -203,7 +205,7 @@ IMPLEMENT_META_INTERFACE(Memory, "android.utils.IMemory"); BnMemory::BnMemory() { } -BnMemory::~BnMemory() { +BnMemory::~BnMemory() { } status_t BnMemory::onTransact( @@ -229,7 +231,7 @@ status_t BnMemory::onTransact( BpMemoryHeap::BpMemoryHeap(const sp<IBinder>& impl) : BpInterface<IMemoryHeap>(impl), - mHeapId(-1), mBase(MAP_FAILED), mSize(0), mFlags(0), mRealHeap(false) + mHeapId(-1), mBase(MAP_FAILED), mSize(0), mFlags(0), mOffset(0), mRealHeap(false) { } @@ -242,7 +244,7 @@ BpMemoryHeap::~BpMemoryHeap() { sp<IBinder> binder = const_cast<BpMemoryHeap*>(this)->asBinder(); if (VERBOSE) { - LOGD("UNMAPPING binder=%p, heap=%p, size=%d, fd=%d", + LOGD("UNMAPPING binder=%p, heap=%p, size=%d, fd=%d", binder.get(), this, mSize, mHeapId); CallStack stack; stack.update(); @@ -270,6 +272,7 @@ void BpMemoryHeap::assertMapped() const if (mHeapId == -1) { mBase = heap->mBase; mSize = heap->mSize; + mOffset = heap->mOffset; android_atomic_write( dup( heap->mHeapId ), &mHeapId ); } } else { @@ -286,13 +289,14 @@ void BpMemoryHeap::assertReallyMapped() const // remote call without mLock held, worse case scenario, we end up // calling transact() from multiple threads, but that's not a problem, // only mmap below must be in the critical section. - + Parcel data, reply; data.writeInterfaceToken(IMemoryHeap::getInterfaceDescriptor()); status_t err = remote()->transact(HEAP_ID, data, &reply); int parcel_fd = reply.readFileDescriptor(); ssize_t size = reply.readInt32(); uint32_t flags = reply.readInt32(); + uint32_t offset = reply.readInt32(); LOGE_IF(err, "binder=%p transaction failed fd=%d, size=%ld, err=%d (%s)", asBinder().get(), parcel_fd, size, err, strerror(-err)); @@ -309,7 +313,7 @@ void BpMemoryHeap::assertReallyMapped() const Mutex::Autolock _l(mLock); if (mHeapId == -1) { mRealHeap = true; - mBase = mmap(0, size, access, MAP_SHARED, fd, 0); + mBase = mmap(0, size, access, MAP_SHARED, fd, offset); if (mBase == MAP_FAILED) { LOGE("cannot map BpMemoryHeap (binder=%p), size=%ld, fd=%d (%s)", asBinder().get(), size, fd, strerror(errno)); @@ -317,6 +321,7 @@ void BpMemoryHeap::assertReallyMapped() const } else { mSize = size; mFlags = flags; + mOffset = offset; android_atomic_write(fd, &mHeapId); } } @@ -343,14 +348,19 @@ uint32_t BpMemoryHeap::getFlags() const { return mFlags; } +uint32_t BpMemoryHeap::getOffset() const { + assertMapped(); + return mOffset; +} + // --------------------------------------------------------------------------- IMPLEMENT_META_INTERFACE(MemoryHeap, "android.utils.IMemoryHeap"); -BnMemoryHeap::BnMemoryHeap() { +BnMemoryHeap::BnMemoryHeap() { } -BnMemoryHeap::~BnMemoryHeap() { +BnMemoryHeap::~BnMemoryHeap() { } status_t BnMemoryHeap::onTransact( @@ -362,6 +372,7 @@ status_t BnMemoryHeap::onTransact( reply->writeFileDescriptor(getHeapID()); reply->writeInt32(getSize()); reply->writeInt32(getFlags()); + reply->writeInt32(getOffset()); return NO_ERROR; } break; default: @@ -383,17 +394,17 @@ HeapCache::~HeapCache() void HeapCache::binderDied(const wp<IBinder>& binder) { //LOGD("binderDied binder=%p", binder.unsafe_get()); - free_heap(binder); + free_heap(binder); } -sp<IMemoryHeap> HeapCache::find_heap(const sp<IBinder>& binder) +sp<IMemoryHeap> HeapCache::find_heap(const sp<IBinder>& binder) { Mutex::Autolock _l(mHeapCacheLock); ssize_t i = mHeapCache.indexOfKey(binder); if (i>=0) { heap_info_t& info = mHeapCache.editValueAt(i); LOGD_IF(VERBOSE, - "found binder=%p, heap=%p, size=%d, fd=%d, count=%d", + "found binder=%p, heap=%p, size=%d, fd=%d, count=%d", binder.get(), info.heap.get(), static_cast<BpMemoryHeap*>(info.heap.get())->mSize, static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId, @@ -415,7 +426,7 @@ void HeapCache::free_heap(const sp<IBinder>& binder) { free_heap( wp<IBinder>(binder) ); } -void HeapCache::free_heap(const wp<IBinder>& binder) +void HeapCache::free_heap(const wp<IBinder>& binder) { sp<IMemoryHeap> rel; { @@ -426,7 +437,7 @@ void HeapCache::free_heap(const wp<IBinder>& binder) int32_t c = android_atomic_dec(&info.count); if (c == 1) { LOGD_IF(VERBOSE, - "removing binder=%p, heap=%p, size=%d, fd=%d, count=%d", + "removing binder=%p, heap=%p, size=%d, fd=%d, count=%d", binder.unsafe_get(), info.heap.get(), static_cast<BpMemoryHeap*>(info.heap.get())->mSize, static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId, @@ -450,7 +461,7 @@ sp<IMemoryHeap> HeapCache::get_heap(const sp<IBinder>& binder) return realHeap; } -void HeapCache::dump_heaps() +void HeapCache::dump_heaps() { Mutex::Autolock _l(mHeapCacheLock); int c = mHeapCache.size(); @@ -459,7 +470,7 @@ void HeapCache::dump_heaps() BpMemoryHeap const* h(static_cast<BpMemoryHeap const *>(info.heap.get())); LOGD("hey=%p, heap=%p, count=%d, (fd=%d, base=%p, size=%d)", mHeapCache.keyAt(i).unsafe_get(), - info.heap.get(), info.count, + info.heap.get(), info.count, h->mHeapId, h->mBase, h->mSize); } } diff --git a/libs/binder/MemoryHeapBase.cpp b/libs/binder/MemoryHeapBase.cpp index 9f501e2..bf4a73f 100644 --- a/libs/binder/MemoryHeapBase.cpp +++ b/libs/binder/MemoryHeapBase.cpp @@ -40,15 +40,15 @@ namespace android { // --------------------------------------------------------------------------- -MemoryHeapBase::MemoryHeapBase() +MemoryHeapBase::MemoryHeapBase() : mFD(-1), mSize(0), mBase(MAP_FAILED), - mDevice(NULL), mNeedUnmap(false) + mDevice(NULL), mNeedUnmap(false), mOffset(0) { } MemoryHeapBase::MemoryHeapBase(size_t size, uint32_t flags, char const * name) : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags), - mDevice(0), mNeedUnmap(false) + mDevice(0), mNeedUnmap(false), mOffset(0) { const size_t pagesize = getpagesize(); size = ((size + pagesize-1) & ~(pagesize-1)); @@ -65,7 +65,7 @@ MemoryHeapBase::MemoryHeapBase(size_t size, uint32_t flags, char const * name) MemoryHeapBase::MemoryHeapBase(const char* device, size_t size, uint32_t flags) : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags), - mDevice(0), mNeedUnmap(false) + mDevice(0), mNeedUnmap(false), mOffset(0) { int open_flags = O_RDWR; if (flags & NO_CACHING) @@ -84,7 +84,7 @@ MemoryHeapBase::MemoryHeapBase(const char* device, size_t size, uint32_t flags) MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags, uint32_t offset) : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags), - mDevice(0), mNeedUnmap(false) + mDevice(0), mNeedUnmap(false), mOffset(0) { const size_t pagesize = getpagesize(); size = ((size + pagesize-1) & ~(pagesize-1)); @@ -141,6 +141,7 @@ status_t MemoryHeapBase::mapfd(int fd, size_t size, uint32_t offset) } mFD = fd; mSize = size; + mOffset = offset; return NO_ERROR; } @@ -183,5 +184,9 @@ const char* MemoryHeapBase::getDevice() const { return mDevice; } +uint32_t MemoryHeapBase::getOffset() const { + return mOffset; +} + // --------------------------------------------------------------------------- }; // namespace android diff --git a/libs/binder/Permission.cpp b/libs/binder/Permission.cpp deleted file mode 100644 index fd8fe69..0000000 --- a/libs/binder/Permission.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2009 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 <utils/Log.h> -#include <binder/IPCThreadState.h> -#include <binder/IServiceManager.h> -#include <binder/Permission.h> - -namespace android { -// --------------------------------------------------------------------------- - -Permission::Permission(char const* name) - : mPermissionName(name), mPid(getpid()) -{ -} - -Permission::Permission(const String16& name) - : mPermissionName(name), mPid(getpid()) -{ -} - -Permission::Permission(const Permission& rhs) - : mPermissionName(rhs.mPermissionName), - mGranted(rhs.mGranted), - mPid(rhs.mPid) -{ -} - -Permission::~Permission() -{ -} - -bool Permission::operator < (const Permission& rhs) const -{ - return mPermissionName < rhs.mPermissionName; -} - -bool Permission::checkCalling() const -{ - IPCThreadState* ipcState = IPCThreadState::self(); - pid_t pid = ipcState->getCallingPid(); - uid_t uid = ipcState->getCallingUid(); - return doCheckPermission(pid, uid); -} - -bool Permission::check(pid_t pid, uid_t uid) const -{ - return doCheckPermission(pid, uid); -} - -bool Permission::doCheckPermission(pid_t pid, uid_t uid) const -{ - if ((uid == 0) || (pid == mPid)) { - // root and ourselves is always okay - return true; - } else { - // see if we already granted this permission for this uid - Mutex::Autolock _l(mLock); - if (mGranted.indexOf(uid) >= 0) - return true; - } - - bool granted = checkPermission(mPermissionName, pid, uid); - if (granted) { - Mutex::Autolock _l(mLock); - // no need to check again, the old item will be replaced if it is - // already there. - mGranted.add(uid); - } - return granted; -} - -// --------------------------------------------------------------------------- -}; // namespace android diff --git a/libs/binder/PermissionCache.cpp b/libs/binder/PermissionCache.cpp new file mode 100644 index 0000000..7278187 --- /dev/null +++ b/libs/binder/PermissionCache.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2009 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 "PermissionCache" + +#include <stdint.h> +#include <utils/Log.h> +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> +#include <binder/PermissionCache.h> +#include <utils/String8.h> + +namespace android { + +// ---------------------------------------------------------------------------- + +ANDROID_SINGLETON_STATIC_INSTANCE(PermissionCache) ; + +// ---------------------------------------------------------------------------- + +PermissionCache::PermissionCache() { +} + +status_t PermissionCache::check(bool* granted, + const String16& permission, uid_t uid) const { + Mutex::Autolock _l(mLock); + Entry e; + e.name = permission; + e.uid = uid; + ssize_t index = mCache.indexOf(e); + if (index >= 0) { + *granted = mCache.itemAt(index).granted; + return NO_ERROR; + } + return NAME_NOT_FOUND; +} + +void PermissionCache::cache(const String16& permission, + uid_t uid, bool granted) { + Mutex::Autolock _l(mLock); + Entry e; + ssize_t index = mPermissionNamesPool.indexOf(permission); + if (index > 0) { + e.name = mPermissionNamesPool.itemAt(index); + } else { + mPermissionNamesPool.add(permission); + e.name = permission; + } + // note, we don't need to store the pid, which is not actually used in + // permission checks + e.uid = uid; + e.granted = granted; + index = mCache.indexOf(e); + if (index < 0) { + mCache.add(e); + } +} + +void PermissionCache::purge() { + Mutex::Autolock _l(mLock); + mCache.clear(); +} + +bool PermissionCache::checkCallingPermission(const String16& permission) { + return PermissionCache::checkCallingPermission(permission, NULL, NULL); +} + +bool PermissionCache::checkCallingPermission( + const String16& permission, int32_t* outPid, int32_t* outUid) { + IPCThreadState* ipcState = IPCThreadState::self(); + pid_t pid = ipcState->getCallingPid(); + uid_t uid = ipcState->getCallingUid(); + if (outPid) *outPid = pid; + if (outUid) *outUid = uid; + return PermissionCache::checkPermission(permission, pid, uid); +} + +bool PermissionCache::checkPermission( + const String16& permission, pid_t pid, uid_t uid) { + if ((uid == 0) || (pid == getpid())) { + // root and ourselves is always okay + return true; + } + + PermissionCache& pc(PermissionCache::getInstance()); + bool granted = false; + if (pc.check(&granted, permission, uid) != NO_ERROR) { + nsecs_t t = -systemTime(); + granted = android::checkPermission(permission, pid, uid); + t += systemTime(); + LOGD("checking %s for uid=%d => %s (%d us)", + String8(permission).string(), uid, + granted?"granted":"denied", (int)ns2us(t)); + pc.cache(permission, uid, granted); + } + return granted; +} + +// --------------------------------------------------------------------------- +}; // namespace android diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp index 2d4e10d..7264ac4 100644 --- a/libs/binder/ProcessState.cpp +++ b/libs/binder/ProcessState.cpp @@ -43,8 +43,6 @@ #define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2)) -static bool gSingleProcess = false; - // --------------------------------------------------------------------------- @@ -82,12 +80,6 @@ sp<ProcessState> ProcessState::self() return gProcess; } -void ProcessState::setSingleProcess(bool singleProcess) -{ - gSingleProcess = singleProcess; -} - - void ProcessState::setContextObject(const sp<IBinder>& object) { setContextObject(object, String16("default")); @@ -95,11 +87,7 @@ void ProcessState::setContextObject(const sp<IBinder>& object) sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& caller) { - if (supportsProcesses()) { - return getStrongProxyForHandle(0); - } else { - return getContextObject(String16("default"), caller); - } + return getStrongProxyForHandle(0); } void ProcessState::setContextObject(const sp<IBinder>& object, const String16& name) @@ -144,11 +132,6 @@ sp<IBinder> ProcessState::getContextObject(const String16& name, const sp<IBinde return object; } -bool ProcessState::supportsProcesses() const -{ - return mDriverFD >= 0; -} - void ProcessState::startThreadPool() { AutoMutex _l(mLock); @@ -169,24 +152,19 @@ bool ProcessState::becomeContextManager(context_check_func checkFunc, void* user AutoMutex _l(mLock); mBinderContextCheckFunc = checkFunc; mBinderContextUserData = userData; - if (mDriverFD >= 0) { - int dummy = 0; + + int dummy = 0; #if defined(HAVE_ANDROID_OS) - status_t result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy); + status_t result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy); #else - status_t result = INVALID_OPERATION; + status_t result = INVALID_OPERATION; #endif - if (result == 0) { - mManagesContexts = true; - } else if (result == -1) { - mBinderContextCheckFunc = NULL; - mBinderContextUserData = NULL; - LOGE("Binder ioctl to become context manager failed: %s\n", strerror(errno)); - } - } else { - // If there is no driver, our only world is the local - // process so we can always become the context manager there. + if (result == 0) { mManagesContexts = true; + } else if (result == -1) { + mBinderContextCheckFunc = NULL; + mBinderContextUserData = NULL; + LOGE("Binder ioctl to become context manager failed: %s\n", strerror(errno)); } } return mManagesContexts; @@ -322,10 +300,6 @@ void ProcessState::spawnPooledThread(bool isMain) static int open_driver() { - if (gSingleProcess) { - return -1; - } - int fd = open("/dev/binder", O_RDWR); if (fd >= 0) { fcntl(fd, F_SETFD, FD_CLOEXEC); @@ -386,9 +360,8 @@ ProcessState::ProcessState() mDriverFD = -1; #endif } - if (mDriverFD < 0) { - // Need to run without the driver, starting our own thread pool. - } + + LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened. Terminating."); } ProcessState::~ProcessState() diff --git a/libs/camera/Android.mk b/libs/camera/Android.mk index b17b3d2..dc00957 100644 --- a/libs/camera/Android.mk +++ b/libs/camera/Android.mk @@ -6,7 +6,9 @@ LOCAL_SRC_FILES:= \ CameraParameters.cpp \ ICamera.cpp \ ICameraClient.cpp \ - ICameraService.cpp + ICameraService.cpp \ + ICameraRecordingProxy.cpp \ + ICameraRecordingProxyListener.cpp LOCAL_SHARED_LIBRARIES := \ libcutils \ diff --git a/libs/camera/Camera.cpp b/libs/camera/Camera.cpp index 5eb48da..3c00db5 100644 --- a/libs/camera/Camera.cpp +++ b/libs/camera/Camera.cpp @@ -19,11 +19,12 @@ #define LOG_TAG "Camera" #include <utils/Log.h> #include <utils/threads.h> - +#include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> #include <binder/IMemory.h> #include <camera/Camera.h> +#include <camera/ICameraRecordingProxyListener.h> #include <camera/ICameraService.h> #include <surfaceflinger/Surface.h> @@ -236,6 +237,10 @@ void Camera::stopPreview() void Camera::stopRecording() { LOGV("stopRecording"); + { + Mutex::Autolock _l(mLock); + mRecordingProxyListener.clear(); + } sp <ICamera> c = mCamera; if (c == 0) return; c->stopRecording(); @@ -327,6 +332,12 @@ void Camera::setListener(const sp<CameraListener>& listener) mListener = listener; } +void Camera::setRecordingProxyListener(const sp<ICameraRecordingProxyListener>& listener) +{ + Mutex::Autolock _l(mLock); + mRecordingProxyListener = listener; +} + void Camera::setPreviewCallbackFlags(int flag) { LOGV("setPreviewCallbackFlags"); @@ -364,6 +375,19 @@ void Camera::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr) // callback from camera service when timestamped frame is ready void Camera::dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) { + // If recording proxy listener is registered, forward the frame and return. + // The other listener (mListener) is ignored because the receiver needs to + // call releaseRecordingFrame. + sp<ICameraRecordingProxyListener> proxylistener; + { + Mutex::Autolock _l(mLock); + proxylistener = mRecordingProxyListener; + } + if (proxylistener != NULL) { + proxylistener->dataCallbackTimestamp(timestamp, msgType, dataPtr); + return; + } + sp<CameraListener> listener; { Mutex::Autolock _l(mLock); @@ -389,4 +413,34 @@ void Camera::DeathNotifier::binderDied(const wp<IBinder>& who) { LOGW("Camera server died!"); } +sp<ICameraRecordingProxy> Camera::getRecordingProxy() { + LOGV("getProxy"); + return new RecordingProxy(this); +} + +status_t Camera::RecordingProxy::startRecording(const sp<ICameraRecordingProxyListener>& listener) +{ + LOGV("RecordingProxy::startRecording"); + mCamera->setRecordingProxyListener(listener); + mCamera->reconnect(); + return mCamera->startRecording(); +} + +void Camera::RecordingProxy::stopRecording() +{ + LOGV("RecordingProxy::stopRecording"); + mCamera->stopRecording(); +} + +void Camera::RecordingProxy::releaseRecordingFrame(const sp<IMemory>& mem) +{ + LOGV("RecordingProxy::releaseRecordingFrame"); + mCamera->releaseRecordingFrame(mem); +} + +Camera::RecordingProxy::RecordingProxy(const sp<Camera>& camera) +{ + mCamera = camera; +} + }; // namespace android diff --git a/libs/camera/ICameraRecordingProxy.cpp b/libs/camera/ICameraRecordingProxy.cpp new file mode 100644 index 0000000..64b6a5c --- /dev/null +++ b/libs/camera/ICameraRecordingProxy.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2011 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 "ICameraRecordingProxy" +#include <camera/ICameraRecordingProxy.h> +#include <camera/ICameraRecordingProxyListener.h> +#include <binder/IMemory.h> +#include <binder/Parcel.h> +#include <stdint.h> +#include <utils/Log.h> + +namespace android { + +enum { + START_RECORDING = IBinder::FIRST_CALL_TRANSACTION, + STOP_RECORDING, + RELEASE_RECORDING_FRAME, +}; + + +class BpCameraRecordingProxy: public BpInterface<ICameraRecordingProxy> +{ +public: + BpCameraRecordingProxy(const sp<IBinder>& impl) + : BpInterface<ICameraRecordingProxy>(impl) + { + } + + status_t startRecording(const sp<ICameraRecordingProxyListener>& listener) + { + LOGV("startRecording"); + Parcel data, reply; + data.writeInterfaceToken(ICameraRecordingProxy::getInterfaceDescriptor()); + data.writeStrongBinder(listener->asBinder()); + remote()->transact(START_RECORDING, data, &reply); + return reply.readInt32(); + } + + void stopRecording() + { + LOGV("stopRecording"); + Parcel data, reply; + data.writeInterfaceToken(ICameraRecordingProxy::getInterfaceDescriptor()); + remote()->transact(STOP_RECORDING, data, &reply); + } + + void releaseRecordingFrame(const sp<IMemory>& mem) + { + LOGV("releaseRecordingFrame"); + Parcel data, reply; + data.writeInterfaceToken(ICameraRecordingProxy::getInterfaceDescriptor()); + data.writeStrongBinder(mem->asBinder()); + remote()->transact(RELEASE_RECORDING_FRAME, data, &reply); + } +}; + +IMPLEMENT_META_INTERFACE(CameraRecordingProxy, "android.hardware.ICameraRecordingProxy"); + +// ---------------------------------------------------------------------- + +status_t BnCameraRecordingProxy::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch(code) { + case START_RECORDING: { + LOGV("START_RECORDING"); + CHECK_INTERFACE(ICameraRecordingProxy, data, reply); + sp<ICameraRecordingProxyListener> listener = + interface_cast<ICameraRecordingProxyListener>(data.readStrongBinder()); + reply->writeInt32(startRecording(listener)); + return NO_ERROR; + } break; + case STOP_RECORDING: { + LOGV("STOP_RECORDING"); + CHECK_INTERFACE(ICameraRecordingProxy, data, reply); + stopRecording(); + return NO_ERROR; + } break; + case RELEASE_RECORDING_FRAME: { + LOGV("RELEASE_RECORDING_FRAME"); + CHECK_INTERFACE(ICameraRecordingProxy, data, reply); + sp<IMemory> mem = interface_cast<IMemory>(data.readStrongBinder()); + releaseRecordingFrame(mem); + return NO_ERROR; + } break; + + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +// ---------------------------------------------------------------------------- + +}; // namespace android + diff --git a/libs/camera/ICameraRecordingProxyListener.cpp b/libs/camera/ICameraRecordingProxyListener.cpp new file mode 100644 index 0000000..f8cece5 --- /dev/null +++ b/libs/camera/ICameraRecordingProxyListener.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2011 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 "ICameraRecordingProxyListener" +#include <camera/ICameraRecordingProxyListener.h> +#include <binder/IMemory.h> +#include <binder/Parcel.h> +#include <utils/Log.h> + +namespace android { + +enum { + DATA_CALLBACK_TIMESTAMP = IBinder::FIRST_CALL_TRANSACTION, +}; + +class BpCameraRecordingProxyListener: public BpInterface<ICameraRecordingProxyListener> +{ +public: + BpCameraRecordingProxyListener(const sp<IBinder>& impl) + : BpInterface<ICameraRecordingProxyListener>(impl) + { + } + + void dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& imageData) + { + LOGV("dataCallback"); + Parcel data, reply; + data.writeInterfaceToken(ICameraRecordingProxyListener::getInterfaceDescriptor()); + data.writeInt64(timestamp); + data.writeInt32(msgType); + data.writeStrongBinder(imageData->asBinder()); + remote()->transact(DATA_CALLBACK_TIMESTAMP, data, &reply, IBinder::FLAG_ONEWAY); + } +}; + +IMPLEMENT_META_INTERFACE(CameraRecordingProxyListener, "android.hardware.ICameraRecordingProxyListener"); + +// ---------------------------------------------------------------------- + +status_t BnCameraRecordingProxyListener::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch(code) { + case DATA_CALLBACK_TIMESTAMP: { + LOGV("DATA_CALLBACK_TIMESTAMP"); + CHECK_INTERFACE(ICameraRecordingProxyListener, data, reply); + nsecs_t timestamp = data.readInt64(); + int32_t msgType = data.readInt32(); + sp<IMemory> imageData = interface_cast<IMemory>(data.readStrongBinder()); + dataCallbackTimestamp(timestamp, msgType, imageData); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +// ---------------------------------------------------------------------------- + +}; // namespace android + diff --git a/libs/gui/IGraphicBufferAlloc.cpp b/libs/gui/IGraphicBufferAlloc.cpp index 0cd51da..30f8d00 100644 --- a/libs/gui/IGraphicBufferAlloc.cpp +++ b/libs/gui/IGraphicBufferAlloc.cpp @@ -43,7 +43,7 @@ public: } virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h, - PixelFormat format, uint32_t usage) { + PixelFormat format, uint32_t usage, status_t* error) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferAlloc::getInterfaceDescriptor()); data.writeInt32(w); @@ -52,14 +52,15 @@ public: data.writeInt32(usage); remote()->transact(CREATE_GRAPHIC_BUFFER, data, &reply); sp<GraphicBuffer> graphicBuffer; - bool nonNull = (bool)reply.readInt32(); - if (nonNull) { + status_t result = reply.readInt32(); + if (result == NO_ERROR) { graphicBuffer = new GraphicBuffer(); reply.read(*graphicBuffer); // reply.readStrongBinder(); // here we don't even have to read the BufferReference from // the parcel, it'll die with the parcel. } + *error = result; return graphicBuffer; } }; @@ -91,8 +92,10 @@ status_t BnGraphicBufferAlloc::onTransact( uint32_t h = data.readInt32(); PixelFormat format = data.readInt32(); uint32_t usage = data.readInt32(); - sp<GraphicBuffer> result(createGraphicBuffer(w, h, format, usage)); - reply->writeInt32(result != 0); + status_t error; + sp<GraphicBuffer> result = + createGraphicBuffer(w, h, format, usage, &error); + reply->writeInt32(error); if (result != 0) { reply->write(*result); // We add a BufferReference to this parcel to make sure the diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 40450a3..c1156d5 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -25,6 +25,8 @@ #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> +#include <private/surfaceflinger/LayerState.h> + #include <surfaceflinger/ISurfaceComposer.h> #include <ui/DisplayInfo.h> @@ -74,18 +76,17 @@ public: return interface_cast<IMemoryHeap>(reply.readStrongBinder()); } - virtual void openGlobalTransaction() + virtual void setTransactionState(const Vector<ComposerState>& state) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - remote()->transact(BnSurfaceComposer::OPEN_GLOBAL_TRANSACTION, data, &reply); - } - - virtual void closeGlobalTransaction() - { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - remote()->transact(BnSurfaceComposer::CLOSE_GLOBAL_TRANSACTION, data, &reply); + Vector<ComposerState>::const_iterator b(state.begin()); + Vector<ComposerState>::const_iterator e(state.end()); + data.writeInt32(state.size()); + for ( ; b != e ; ++b ) { + b->write(data); + } + remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply); } virtual status_t freezeDisplay(DisplayID dpy, uint32_t flags) @@ -218,13 +219,17 @@ status_t BnSurfaceComposer::onTransact( sp<IBinder> b = createGraphicBufferAlloc()->asBinder(); reply->writeStrongBinder(b); } break; - case OPEN_GLOBAL_TRANSACTION: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - openGlobalTransaction(); - } break; - case CLOSE_GLOBAL_TRANSACTION: { + case SET_TRANSACTION_STATE: { CHECK_INTERFACE(ISurfaceComposer, data, reply); - closeGlobalTransaction(); + size_t count = data.readInt32(); + ComposerState s; + Vector<ComposerState> state; + state.setCapacity(count); + for (size_t i=0 ; i<count ; i++) { + s.read(data); + state.add(s); + } + setTransactionState(state); } break; case SET_ORIENTATION: { CHECK_INTERFACE(ISurfaceComposer, data, reply); diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp index 8d83392..bc97cac 100644 --- a/libs/gui/ISurfaceComposerClient.cpp +++ b/libs/gui/ISurfaceComposerClient.cpp @@ -51,8 +51,7 @@ namespace android { enum { CREATE_SURFACE = IBinder::FIRST_CALL_TRANSACTION, - DESTROY_SURFACE, - SET_STATE + DESTROY_SURFACE }; class BpSurfaceComposerClient : public BpInterface<ISurfaceComposerClient> @@ -92,17 +91,6 @@ public: remote()->transact(DESTROY_SURFACE, data, &reply); return reply.readInt32(); } - - virtual status_t setState(int32_t count, const layer_state_t* states) - { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor()); - data.writeInt32(count); - for (int i=0 ; i<count ; i++) - states[i].write(data); - remote()->transact(SET_STATE, data, &reply); - return reply.readInt32(); - } }; IMPLEMENT_META_INTERFACE(SurfaceComposerClient, "android.ui.ISurfaceComposerClient"); @@ -133,17 +121,6 @@ status_t BnSurfaceComposerClient::onTransact( reply->writeInt32( destroySurface( data.readInt32() ) ); return NO_ERROR; } break; - case SET_STATE: { - CHECK_INTERFACE(ISurfaceComposerClient, data, reply); - int32_t count = data.readInt32(); - layer_state_t* states = new layer_state_t[count]; - for (int i=0 ; i<count ; i++) - states[i].read(data); - status_t err = setState(count, states); - delete [] states; - reply->writeInt32(err); - return NO_ERROR; - } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 01c4c7e..87901e8 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -17,6 +17,7 @@ #include <utils/Errors.h> #include <binder/Parcel.h> #include <private/surfaceflinger/LayerState.h> +#include <surfaceflinger/ISurfaceComposerClient.h> namespace android { @@ -58,4 +59,14 @@ status_t layer_state_t::read(const Parcel& input) return NO_ERROR; } +status_t ComposerState::write(Parcel& output) const { + output.writeStrongBinder(client->asBinder()); + return state.write(output); +} + +status_t ComposerState::read(const Parcel& input) { + client = interface_cast<ISurfaceComposerClient>(input.readStrongBinder()); + return state.read(input); +} + }; // namespace android diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 1678711..8cead80 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -74,75 +74,52 @@ static inline surface_flinger_cblk_t const volatile * get_cblk() { // --------------------------------------------------------------------------- +// NOTE: this is NOT a member function (it's a friend defined with its +// declaration). +static inline +int compare_type( const ComposerState& lhs, const ComposerState& rhs) { + if (lhs.client < rhs.client) return -1; + if (lhs.client > rhs.client) return 1; + if (lhs.state.surface < rhs.state.surface) return -1; + if (lhs.state.surface > rhs.state.surface) return 1; + return 0; +} + class Composer : public Singleton<Composer> { - Mutex mLock; - SortedVector< wp<SurfaceComposerClient> > mActiveConnections; - SortedVector<sp<SurfaceComposerClient> > mOpenTransactions; + friend class Singleton<Composer>; - Composer() : Singleton<Composer>() { - } + mutable Mutex mLock; + SortedVector<ComposerState> mStates; - void addClientImpl(const sp<SurfaceComposerClient>& client) { - Mutex::Autolock _l(mLock); - mActiveConnections.add(client); - } + Composer() : Singleton<Composer>() { } - void removeClientImpl(const sp<SurfaceComposerClient>& client) { - Mutex::Autolock _l(mLock); - mActiveConnections.remove(client); - } + void closeGlobalTransactionImpl(); - void openGlobalTransactionImpl() - { - Mutex::Autolock _l(mLock); - if (mOpenTransactions.size()) { - LOGE("openGlobalTransaction() called more than once. skipping."); - return; - } - const size_t N = mActiveConnections.size(); - for (size_t i=0; i<N; i++) { - sp<SurfaceComposerClient> client(mActiveConnections[i].promote()); - if (client != 0 && mOpenTransactions.indexOf(client) < 0) { - if (client->openTransaction() == NO_ERROR) { - mOpenTransactions.add(client); - } else { - LOGE("openTransaction on client %p failed", client.get()); - // let it go, it'll fail later when the user - // tries to do something with the transaction - } - } - } - } + layer_state_t* getLayerStateLocked( + const sp<SurfaceComposerClient>& client, SurfaceID id); - void closeGlobalTransactionImpl() - { - mLock.lock(); - SortedVector< sp<SurfaceComposerClient> > clients(mOpenTransactions); - mOpenTransactions.clear(); - mLock.unlock(); - - sp<ISurfaceComposer> sm(getComposerService()); - sm->openGlobalTransaction(); - const size_t N = clients.size(); - for (size_t i=0; i<N; i++) { - clients[i]->closeTransaction(); - } - sm->closeGlobalTransaction(); - } +public: - friend class Singleton<Composer>; + status_t setPosition(const sp<SurfaceComposerClient>& client, SurfaceID id, + int32_t x, int32_t y); + status_t setSize(const sp<SurfaceComposerClient>& client, SurfaceID id, + uint32_t w, uint32_t h); + status_t setLayer(const sp<SurfaceComposerClient>& client, SurfaceID id, + int32_t z); + status_t setFlags(const sp<SurfaceComposerClient>& client, SurfaceID id, + uint32_t flags, uint32_t mask); + status_t setTransparentRegionHint( + const sp<SurfaceComposerClient>& client, SurfaceID id, + const Region& transparentRegion); + status_t setAlpha(const sp<SurfaceComposerClient>& client, SurfaceID id, + float alpha); + status_t setMatrix(const sp<SurfaceComposerClient>& client, SurfaceID id, + float dsdx, float dtdx, float dsdy, float dtdy); + status_t setFreezeTint( + const sp<SurfaceComposerClient>& client, SurfaceID id, + uint32_t tint); -public: - static void addClient(const sp<SurfaceComposerClient>& client) { - Composer::getInstance().addClientImpl(client); - } - static void removeClient(const sp<SurfaceComposerClient>& client) { - Composer::getInstance().removeClientImpl(client); - } - static void openGlobalTransaction() { - Composer::getInstance().openGlobalTransactionImpl(); - } static void closeGlobalTransaction() { Composer::getInstance().closeGlobalTransactionImpl(); } @@ -152,127 +129,185 @@ ANDROID_SINGLETON_STATIC_INSTANCE(Composer); // --------------------------------------------------------------------------- -static inline int compare_type( const layer_state_t& lhs, - const layer_state_t& rhs) { - if (lhs.surface < rhs.surface) return -1; - if (lhs.surface > rhs.surface) return 1; - return 0; +void Composer::closeGlobalTransactionImpl() { + sp<ISurfaceComposer> sm(getComposerService()); + + Vector<ComposerState> transaction; + + { // scope for the lock + Mutex::Autolock _l(mLock); + transaction = mStates; + mStates.clear(); + } + + sm->setTransactionState(transaction); +} + +layer_state_t* Composer::getLayerStateLocked( + const sp<SurfaceComposerClient>& client, SurfaceID id) { + + ComposerState s; + s.client = client->mClient; + s.state.surface = id; + + ssize_t index = mStates.indexOf(s); + if (index < 0) { + // we don't have it, add an initialized layer_state to our list + index = mStates.add(s); + } + + ComposerState* const out = mStates.editArray(); + return &(out[index].state); +} + +status_t Composer::setPosition(const sp<SurfaceComposerClient>& client, + SurfaceID id, int32_t x, int32_t y) { + Mutex::Autolock _l(mLock); + layer_state_t* s = getLayerStateLocked(client, id); + if (!s) + return BAD_INDEX; + s->what |= ISurfaceComposer::ePositionChanged; + s->x = x; + s->y = y; + return NO_ERROR; +} + +status_t Composer::setSize(const sp<SurfaceComposerClient>& client, + SurfaceID id, uint32_t w, uint32_t h) { + Mutex::Autolock _l(mLock); + layer_state_t* s = getLayerStateLocked(client, id); + if (!s) + return BAD_INDEX; + s->what |= ISurfaceComposer::eSizeChanged; + s->w = w; + s->h = h; + return NO_ERROR; +} + +status_t Composer::setLayer(const sp<SurfaceComposerClient>& client, + SurfaceID id, int32_t z) { + Mutex::Autolock _l(mLock); + layer_state_t* s = getLayerStateLocked(client, id); + if (!s) + return BAD_INDEX; + s->what |= ISurfaceComposer::eLayerChanged; + s->z = z; + return NO_ERROR; +} + +status_t Composer::setFlags(const sp<SurfaceComposerClient>& client, + SurfaceID id, uint32_t flags, + uint32_t mask) { + Mutex::Autolock _l(mLock); + layer_state_t* s = getLayerStateLocked(client, id); + if (!s) + return BAD_INDEX; + s->what |= ISurfaceComposer::eVisibilityChanged; + s->flags &= ~mask; + s->flags |= (flags & mask); + s->mask |= mask; + return NO_ERROR; +} + +status_t Composer::setTransparentRegionHint( + const sp<SurfaceComposerClient>& client, SurfaceID id, + const Region& transparentRegion) { + Mutex::Autolock _l(mLock); + layer_state_t* s = getLayerStateLocked(client, id); + if (!s) + return BAD_INDEX; + s->what |= ISurfaceComposer::eTransparentRegionChanged; + s->transparentRegion = transparentRegion; + return NO_ERROR; +} + +status_t Composer::setAlpha(const sp<SurfaceComposerClient>& client, + SurfaceID id, float alpha) { + Mutex::Autolock _l(mLock); + layer_state_t* s = getLayerStateLocked(client, id); + if (!s) + return BAD_INDEX; + s->what |= ISurfaceComposer::eAlphaChanged; + s->alpha = alpha; + return NO_ERROR; +} + +status_t Composer::setMatrix(const sp<SurfaceComposerClient>& client, + SurfaceID id, float dsdx, float dtdx, + float dsdy, float dtdy) { + Mutex::Autolock _l(mLock); + layer_state_t* s = getLayerStateLocked(client, id); + if (!s) + return BAD_INDEX; + s->what |= ISurfaceComposer::eMatrixChanged; + layer_state_t::matrix22_t matrix; + matrix.dsdx = dsdx; + matrix.dtdx = dtdx; + matrix.dsdy = dsdy; + matrix.dtdy = dtdy; + s->matrix = matrix; + return NO_ERROR; } +status_t Composer::setFreezeTint(const sp<SurfaceComposerClient>& client, + SurfaceID id, uint32_t tint) { + Mutex::Autolock _l(mLock); + layer_state_t* s = getLayerStateLocked(client, id); + if (!s) + return BAD_INDEX; + s->what |= ISurfaceComposer::eFreezeTintChanged; + s->tint = tint; + return NO_ERROR; +} + +// --------------------------------------------------------------------------- + SurfaceComposerClient::SurfaceComposerClient() - : mTransactionOpen(0), mPrebuiltLayerState(0), mStatus(NO_INIT) + : mStatus(NO_INIT), mComposer(Composer::getInstance()) { } -void SurfaceComposerClient::onFirstRef() -{ +void SurfaceComposerClient::onFirstRef() { sp<ISurfaceComposer> sm(getComposerService()); if (sm != 0) { sp<ISurfaceComposerClient> conn = sm->createConnection(); if (conn != 0) { mClient = conn; - Composer::addClient(this); - mPrebuiltLayerState = new layer_state_t; mStatus = NO_ERROR; } } } -SurfaceComposerClient::~SurfaceComposerClient() -{ - delete mPrebuiltLayerState; +SurfaceComposerClient::~SurfaceComposerClient() { dispose(); } -status_t SurfaceComposerClient::initCheck() const -{ +status_t SurfaceComposerClient::initCheck() const { return mStatus; } -sp<IBinder> SurfaceComposerClient::connection() const -{ +sp<IBinder> SurfaceComposerClient::connection() const { return (mClient != 0) ? mClient->asBinder() : 0; } status_t SurfaceComposerClient::linkToComposerDeath( const sp<IBinder::DeathRecipient>& recipient, - void* cookie, uint32_t flags) -{ + void* cookie, uint32_t flags) { sp<ISurfaceComposer> sm(getComposerService()); return sm->asBinder()->linkToDeath(recipient, cookie, flags); } -void SurfaceComposerClient::dispose() -{ +void SurfaceComposerClient::dispose() { // this can be called more than once. sp<ISurfaceComposerClient> client; Mutex::Autolock _lm(mLock); if (mClient != 0) { - Composer::removeClient(this); client = mClient; // hold ref while lock is held mClient.clear(); } mStatus = NO_INIT; } -status_t SurfaceComposerClient::getDisplayInfo( - DisplayID dpy, DisplayInfo* info) -{ - if (uint32_t(dpy)>=NUM_DISPLAY_MAX) - return BAD_VALUE; - - volatile surface_flinger_cblk_t const * cblk = get_cblk(); - volatile display_cblk_t const * dcblk = cblk->displays + dpy; - - info->w = dcblk->w; - info->h = dcblk->h; - info->orientation = dcblk->orientation; - info->xdpi = dcblk->xdpi; - info->ydpi = dcblk->ydpi; - info->fps = dcblk->fps; - info->density = dcblk->density; - return getPixelFormatInfo(dcblk->format, &(info->pixelFormatInfo)); -} - -ssize_t SurfaceComposerClient::getDisplayWidth(DisplayID dpy) -{ - if (uint32_t(dpy)>=NUM_DISPLAY_MAX) - return BAD_VALUE; - volatile surface_flinger_cblk_t const * cblk = get_cblk(); - volatile display_cblk_t const * dcblk = cblk->displays + dpy; - return dcblk->w; -} - -ssize_t SurfaceComposerClient::getDisplayHeight(DisplayID dpy) -{ - if (uint32_t(dpy)>=NUM_DISPLAY_MAX) - return BAD_VALUE; - volatile surface_flinger_cblk_t const * cblk = get_cblk(); - volatile display_cblk_t const * dcblk = cblk->displays + dpy; - return dcblk->h; -} - -ssize_t SurfaceComposerClient::getDisplayOrientation(DisplayID dpy) -{ - if (uint32_t(dpy)>=NUM_DISPLAY_MAX) - return BAD_VALUE; - volatile surface_flinger_cblk_t const * cblk = get_cblk(); - volatile display_cblk_t const * dcblk = cblk->displays + dpy; - return dcblk->orientation; -} - -ssize_t SurfaceComposerClient::getNumberOfDisplays() -{ - volatile surface_flinger_cblk_t const * cblk = get_cblk(); - uint32_t connected = cblk->connected; - int n = 0; - while (connected) { - if (connected&1) n++; - connected >>= 1; - } - return n; -} - sp<SurfaceControl> SurfaceComposerClient::createSurface( DisplayID display, uint32_t w, @@ -310,237 +345,167 @@ sp<SurfaceControl> SurfaceComposerClient::createSurface( return result; } -status_t SurfaceComposerClient::destroySurface(SurfaceID sid) -{ +status_t SurfaceComposerClient::destroySurface(SurfaceID sid) { if (mStatus != NO_ERROR) return mStatus; - - // it's okay to destroy a surface while a transaction is open, - // (transactions really are a client-side concept) - // however, this indicates probably a misuse of the API or a bug - // in the client code. - LOGW_IF(mTransactionOpen, - "Destroying surface while a transaction is open. " - "Client %p: destroying surface %d, mTransactionOpen=%d", - this, sid, mTransactionOpen); - status_t err = mClient->destroySurface(sid); return err; } -void SurfaceComposerClient::openGlobalTransaction() -{ - Composer::openGlobalTransaction(); +inline Composer& SurfaceComposerClient::getComposer() { + return mComposer; } -void SurfaceComposerClient::closeGlobalTransaction() -{ - Composer::closeGlobalTransaction(); -} +// ---------------------------------------------------------------------------- -status_t SurfaceComposerClient::freezeDisplay(DisplayID dpy, uint32_t flags) -{ - sp<ISurfaceComposer> sm(getComposerService()); - return sm->freezeDisplay(dpy, flags); +void SurfaceComposerClient::openGlobalTransaction() { + // Currently a no-op } -status_t SurfaceComposerClient::unfreezeDisplay(DisplayID dpy, uint32_t flags) -{ - sp<ISurfaceComposer> sm(getComposerService()); - return sm->unfreezeDisplay(dpy, flags); +void SurfaceComposerClient::closeGlobalTransaction() { + Composer::closeGlobalTransaction(); } -int SurfaceComposerClient::setOrientation(DisplayID dpy, - int orientation, uint32_t flags) -{ - sp<ISurfaceComposer> sm(getComposerService()); - return sm->setOrientation(dpy, orientation, flags); -} +// ---------------------------------------------------------------------------- -status_t SurfaceComposerClient::openTransaction() -{ - if (mStatus != NO_ERROR) - return mStatus; - Mutex::Autolock _l(mLock); - mTransactionOpen++; - return NO_ERROR; +status_t SurfaceComposerClient::setFreezeTint(SurfaceID id, uint32_t tint) { + return getComposer().setFreezeTint(this, id, tint); } -status_t SurfaceComposerClient::closeTransaction() -{ - if (mStatus != NO_ERROR) - return mStatus; - - Mutex::Autolock _l(mLock); - if (mTransactionOpen <= 0) { - LOGE( "closeTransaction (client %p, mTransactionOpen=%d) " - "called more times than openTransaction()", - this, mTransactionOpen); - return INVALID_OPERATION; - } +status_t SurfaceComposerClient::setPosition(SurfaceID id, int32_t x, int32_t y) { + return getComposer().setPosition(this, id, x, y); +} - if (mTransactionOpen >= 2) { - mTransactionOpen--; - return NO_ERROR; - } +status_t SurfaceComposerClient::setSize(SurfaceID id, uint32_t w, uint32_t h) { + return getComposer().setSize(this, id, w, h); +} - mTransactionOpen = 0; - const ssize_t count = mStates.size(); - if (count) { - mClient->setState(count, mStates.array()); - mStates.clear(); - } - return NO_ERROR; +status_t SurfaceComposerClient::setLayer(SurfaceID id, int32_t z) { + return getComposer().setLayer(this, id, z); } -layer_state_t* SurfaceComposerClient::get_state_l(SurfaceID index) -{ - // API usage error, do nothing. - if (mTransactionOpen<=0) { - LOGE("Not in transaction (client=%p, SurfaceID=%d, mTransactionOpen=%d", - this, int(index), mTransactionOpen); - return 0; - } +status_t SurfaceComposerClient::hide(SurfaceID id) { + return getComposer().setFlags(this, id, + ISurfaceComposer::eLayerHidden, + ISurfaceComposer::eLayerHidden); +} - // use mPrebuiltLayerState just to find out if we already have it - layer_state_t& dummy(*mPrebuiltLayerState); - dummy.surface = index; - ssize_t i = mStates.indexOf(dummy); - if (i < 0) { - // we don't have it, add an initialized layer_state to our list - i = mStates.add(dummy); - } - return mStates.editArray() + i; +status_t SurfaceComposerClient::show(SurfaceID id, int32_t) { + return getComposer().setFlags(this, id, + 0, + ISurfaceComposer::eLayerHidden); } -layer_state_t* SurfaceComposerClient::lockLayerState(SurfaceID id) -{ - layer_state_t* s; - mLock.lock(); - s = get_state_l(id); - if (!s) mLock.unlock(); - return s; +status_t SurfaceComposerClient::freeze(SurfaceID id) { + return getComposer().setFlags(this, id, + ISurfaceComposer::eLayerFrozen, + ISurfaceComposer::eLayerFrozen); } -void SurfaceComposerClient::unlockLayerState() -{ - mLock.unlock(); +status_t SurfaceComposerClient::unfreeze(SurfaceID id) { + return getComposer().setFlags(this, id, + 0, + ISurfaceComposer::eLayerFrozen); } -status_t SurfaceComposerClient::setPosition(SurfaceID id, int32_t x, int32_t y) -{ - layer_state_t* s = lockLayerState(id); - if (!s) return BAD_INDEX; - s->what |= ISurfaceComposer::ePositionChanged; - s->x = x; - s->y = y; - unlockLayerState(); - return NO_ERROR; +status_t SurfaceComposerClient::setFlags(SurfaceID id, uint32_t flags, + uint32_t mask) { + return getComposer().setFlags(this, id, flags, mask); } -status_t SurfaceComposerClient::setSize(SurfaceID id, uint32_t w, uint32_t h) -{ - layer_state_t* s = lockLayerState(id); - if (!s) return BAD_INDEX; - s->what |= ISurfaceComposer::eSizeChanged; - s->w = w; - s->h = h; - unlockLayerState(); - return NO_ERROR; +status_t SurfaceComposerClient::setTransparentRegionHint(SurfaceID id, + const Region& transparentRegion) { + return getComposer().setTransparentRegionHint(this, id, transparentRegion); } -status_t SurfaceComposerClient::setLayer(SurfaceID id, int32_t z) -{ - layer_state_t* s = lockLayerState(id); - if (!s) return BAD_INDEX; - s->what |= ISurfaceComposer::eLayerChanged; - s->z = z; - unlockLayerState(); - return NO_ERROR; +status_t SurfaceComposerClient::setAlpha(SurfaceID id, float alpha) { + return getComposer().setAlpha(this, id, alpha); } -status_t SurfaceComposerClient::hide(SurfaceID id) -{ - return setFlags(id, ISurfaceComposer::eLayerHidden, - ISurfaceComposer::eLayerHidden); +status_t SurfaceComposerClient::setMatrix(SurfaceID id, float dsdx, float dtdx, + float dsdy, float dtdy) { + return getComposer().setMatrix(this, id, dsdx, dtdx, dsdy, dtdy); } -status_t SurfaceComposerClient::show(SurfaceID id, int32_t) +// ---------------------------------------------------------------------------- + +status_t SurfaceComposerClient::getDisplayInfo( + DisplayID dpy, DisplayInfo* info) { - return setFlags(id, 0, ISurfaceComposer::eLayerHidden); + if (uint32_t(dpy)>=NUM_DISPLAY_MAX) + return BAD_VALUE; + + volatile surface_flinger_cblk_t const * cblk = get_cblk(); + volatile display_cblk_t const * dcblk = cblk->displays + dpy; + + info->w = dcblk->w; + info->h = dcblk->h; + info->orientation = dcblk->orientation; + info->xdpi = dcblk->xdpi; + info->ydpi = dcblk->ydpi; + info->fps = dcblk->fps; + info->density = dcblk->density; + return getPixelFormatInfo(dcblk->format, &(info->pixelFormatInfo)); } -status_t SurfaceComposerClient::freeze(SurfaceID id) +ssize_t SurfaceComposerClient::getDisplayWidth(DisplayID dpy) { - return setFlags(id, ISurfaceComposer::eLayerFrozen, - ISurfaceComposer::eLayerFrozen); + if (uint32_t(dpy)>=NUM_DISPLAY_MAX) + return BAD_VALUE; + volatile surface_flinger_cblk_t const * cblk = get_cblk(); + volatile display_cblk_t const * dcblk = cblk->displays + dpy; + return dcblk->w; } -status_t SurfaceComposerClient::unfreeze(SurfaceID id) +ssize_t SurfaceComposerClient::getDisplayHeight(DisplayID dpy) { - return setFlags(id, 0, ISurfaceComposer::eLayerFrozen); + if (uint32_t(dpy)>=NUM_DISPLAY_MAX) + return BAD_VALUE; + volatile surface_flinger_cblk_t const * cblk = get_cblk(); + volatile display_cblk_t const * dcblk = cblk->displays + dpy; + return dcblk->h; } -status_t SurfaceComposerClient::setFlags(SurfaceID id, - uint32_t flags, uint32_t mask) +ssize_t SurfaceComposerClient::getDisplayOrientation(DisplayID dpy) { - layer_state_t* s = lockLayerState(id); - if (!s) return BAD_INDEX; - s->what |= ISurfaceComposer::eVisibilityChanged; - s->flags &= ~mask; - s->flags |= (flags & mask); - s->mask |= mask; - unlockLayerState(); - return NO_ERROR; + if (uint32_t(dpy)>=NUM_DISPLAY_MAX) + return BAD_VALUE; + volatile surface_flinger_cblk_t const * cblk = get_cblk(); + volatile display_cblk_t const * dcblk = cblk->displays + dpy; + return dcblk->orientation; } -status_t SurfaceComposerClient::setTransparentRegionHint( - SurfaceID id, const Region& transparentRegion) +ssize_t SurfaceComposerClient::getNumberOfDisplays() { - layer_state_t* s = lockLayerState(id); - if (!s) return BAD_INDEX; - s->what |= ISurfaceComposer::eTransparentRegionChanged; - s->transparentRegion = transparentRegion; - unlockLayerState(); - return NO_ERROR; + volatile surface_flinger_cblk_t const * cblk = get_cblk(); + uint32_t connected = cblk->connected; + int n = 0; + while (connected) { + if (connected&1) n++; + connected >>= 1; + } + return n; } -status_t SurfaceComposerClient::setAlpha(SurfaceID id, float alpha) +// ---------------------------------------------------------------------------- + +status_t SurfaceComposerClient::freezeDisplay(DisplayID dpy, uint32_t flags) { - layer_state_t* s = lockLayerState(id); - if (!s) return BAD_INDEX; - s->what |= ISurfaceComposer::eAlphaChanged; - s->alpha = alpha; - unlockLayerState(); - return NO_ERROR; + sp<ISurfaceComposer> sm(getComposerService()); + return sm->freezeDisplay(dpy, flags); } -status_t SurfaceComposerClient::setMatrix( - SurfaceID id, - float dsdx, float dtdx, - float dsdy, float dtdy ) +status_t SurfaceComposerClient::unfreezeDisplay(DisplayID dpy, uint32_t flags) { - layer_state_t* s = lockLayerState(id); - if (!s) return BAD_INDEX; - s->what |= ISurfaceComposer::eMatrixChanged; - layer_state_t::matrix22_t matrix; - matrix.dsdx = dsdx; - matrix.dtdx = dtdx; - matrix.dsdy = dsdy; - matrix.dtdy = dtdy; - s->matrix = matrix; - unlockLayerState(); - return NO_ERROR; + sp<ISurfaceComposer> sm(getComposerService()); + return sm->unfreezeDisplay(dpy, flags); } -status_t SurfaceComposerClient::setFreezeTint(SurfaceID id, uint32_t tint) +int SurfaceComposerClient::setOrientation(DisplayID dpy, + int orientation, uint32_t flags) { - layer_state_t* s = lockLayerState(id); - if (!s) return BAD_INDEX; - s->what |= ISurfaceComposer::eFreezeTintChanged; - s->tint = tint; - unlockLayerState(); - return NO_ERROR; + sp<ISurfaceComposer> sm(getComposerService()); + return sm->setOrientation(dpy, orientation, flags); } // ---------------------------------------------------------------------------- diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp index 37e6d11..886a3fb 100644 --- a/libs/gui/SurfaceTexture.cpp +++ b/libs/gui/SurfaceTexture.cpp @@ -148,6 +148,11 @@ status_t SurfaceTexture::setBufferCount(int bufferCount) { LOGV("SurfaceTexture::setBufferCount"); Mutex::Autolock lock(mMutex); + if (bufferCount > NUM_BUFFER_SLOTS) { + LOGE("setBufferCount: bufferCount larger than slots available"); + return BAD_VALUE; + } + // Error out if the user has dequeued buffers for (int i=0 ; i<mBufferCount ; i++) { if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) { @@ -208,7 +213,7 @@ status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { LOGV("SurfaceTexture::dequeueBuffer"); - if ((w && !h) || (!w & h)) { + if ((w && !h) || (!w && h)) { LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h); return BAD_VALUE; } @@ -347,11 +352,13 @@ status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, ((uint32_t(buffer->usage) & usage) != usage)) { usage |= GraphicBuffer::USAGE_HW_TEXTURE; + status_t error; sp<GraphicBuffer> graphicBuffer( - mGraphicBufferAlloc->createGraphicBuffer(w, h, format, usage)); + mGraphicBufferAlloc->createGraphicBuffer( + w, h, format, usage, &error)); if (graphicBuffer == 0) { LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer failed"); - return NO_MEMORY; + return error; } if (updateFormat) { mPixelFormat = format; @@ -417,17 +424,22 @@ status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp) { return -EINVAL; } - if (mQueue.empty()) { - listener = mFrameAvailableListener; - } - if (mSynchronousMode) { - // in synchronous mode we queue all buffers in a FIFO + // In synchronous mode we queue all buffers in a FIFO. mQueue.push_back(buf); + + // Synchronous mode always signals that an additional frame should + // be consumed. + listener = mFrameAvailableListener; } else { - // in asynchronous mode we only keep the most recent buffer + // In asynchronous mode we only keep the most recent buffer. if (mQueue.empty()) { mQueue.push_back(buf); + + // Asynchronous mode only signals that a frame should be + // consumed if no previous frame was pending. If a frame were + // pending then the consumer would have already been notified. + listener = mFrameAvailableListener; } else { Fifo::iterator front(mQueue.begin()); // buffer currently queued is freed @@ -483,24 +495,14 @@ status_t SurfaceTexture::setTransform(uint32_t transform) { status_t SurfaceTexture::updateTexImage() { LOGV("SurfaceTexture::updateTexImage"); - Mutex::Autolock lock(mMutex); - int buf = mCurrentTexture; + // In asynchronous mode the list is guaranteed to be one buffer + // deep, while in synchronous mode we use the oldest buffer. if (!mQueue.empty()) { - // in asynchronous mode the list is guaranteed to be one buffer deep, - // while in synchronous mode we use the oldest buffer Fifo::iterator front(mQueue.begin()); - buf = *front; - mQueue.erase(front); - if (mQueue.isEmpty()) { - mDequeueCondition.signal(); - } - } + int buf = *front; - // Initially both mCurrentTexture and buf are INVALID_BUFFER_SLOT, - // so this check will fail until a buffer gets queued. - if (mCurrentTexture != buf) { // Update the GL texture object. EGLImageKHR image = mSlots[buf].mEglImage; if (image == EGL_NO_IMAGE_KHR) { @@ -538,7 +540,7 @@ status_t SurfaceTexture::updateTexImage() { } if (mCurrentTexture != INVALID_BUFFER_SLOT) { - // the current buffer becomes FREE if it was still in the queued + // The current buffer becomes FREE if it was still in the queued // state. If it has already been given to the client // (synchronous mode), then it stays in DEQUEUED state. if (mSlots[mCurrentTexture].mBufferState == BufferSlot::QUEUED) @@ -553,17 +555,17 @@ status_t SurfaceTexture::updateTexImage() { mCurrentTransform = mSlots[buf].mTransform; mCurrentTimestamp = mSlots[buf].mTimestamp; computeCurrentTransformMatrix(); + + // Now that we've passed the point at which failures can happen, + // it's safe to remove the buffer from the front of the queue. + mQueue.erase(front); mDequeueCondition.signal(); } else { // We always bind the texture even if we don't update its contents. glBindTexture(mCurrentTextureTarget, mTexName); } - return OK; -} -size_t SurfaceTexture::getQueuedCount() const { - Mutex::Autolock lock(mMutex); - return mQueue.size(); + return OK; } bool SurfaceTexture::isExternalFormat(uint32_t format) @@ -704,10 +706,10 @@ nsecs_t SurfaceTexture::getTimestamp() { } void SurfaceTexture::setFrameAvailableListener( - const sp<FrameAvailableListener>& l) { + const sp<FrameAvailableListener>& listener) { LOGV("SurfaceTexture::setFrameAvailableListener"); Mutex::Autolock lock(mMutex); - mFrameAvailableListener = l; + mFrameAvailableListener = listener; } sp<IBinder> SurfaceTexture::getAllocator() { diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp index f219639..88433fb 100644 --- a/libs/gui/tests/SurfaceTexture_test.cpp +++ b/libs/gui/tests/SurfaceTexture_test.cpp @@ -84,10 +84,10 @@ protected: ASSERT_TRUE(mSurfaceControl != NULL); ASSERT_TRUE(mSurfaceControl->isValid()); - ASSERT_EQ(NO_ERROR, mComposerClient->openTransaction()); + SurfaceComposerClient::openGlobalTransaction(); ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7FFFFFFF)); ASSERT_EQ(NO_ERROR, mSurfaceControl->show()); - ASSERT_EQ(NO_ERROR, mComposerClient->closeTransaction()); + SurfaceComposerClient::closeGlobalTransaction(); sp<ANativeWindow> window = mSurfaceControl->getSurface(); mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig, @@ -419,6 +419,31 @@ protected: ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); } + class FrameWaiter : public SurfaceTexture::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; + }; + sp<SurfaceTexture> mST; sp<SurfaceTextureClient> mSTC; sp<ANativeWindow> mANW; @@ -648,6 +673,157 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferWithCrop) { } } +// This test is intended to catch synchronization bugs between the CPU-written +// and GPU-read buffers. +TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BuffersRepeatedly) { + enum { texWidth = 16 }; + enum { texHeight = 16 }; + enum { numFrames = 1024 }; + + ASSERT_EQ(NO_ERROR, mST->setSynchronousMode(true)); + ASSERT_EQ(NO_ERROR, mST->setBufferCountServer(2)); + ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(), + texWidth, texHeight, HAL_PIXEL_FORMAT_YV12)); + ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(), + GRALLOC_USAGE_SW_WRITE_OFTEN)); + + struct TestPixel { + int x; + int y; + }; + const TestPixel testPixels[] = { + { 4, 11 }, + { 12, 14 }, + { 7, 2 }, + }; + enum {numTestPixels = sizeof(testPixels) / sizeof(testPixels[0])}; + + class ProducerThread : public Thread { + public: + ProducerThread(const sp<ANativeWindow>& anw, const TestPixel* testPixels): + mANW(anw), + mTestPixels(testPixels) { + } + + virtual ~ProducerThread() { + } + + virtual bool threadLoop() { + for (int i = 0; i < numFrames; i++) { + ANativeWindowBuffer* anb; + if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) { + return false; + } + if (anb == NULL) { + return false; + } + + 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(); + int yuvTexStrideY = stride; + int yuvTexOffsetV = yuvTexStrideY * texHeight; + int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf; + int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * texHeight/2; + int yuvTexStrideU = yuvTexStrideV; + + uint8_t* img = NULL; + buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); + + // Gray out all the test pixels first, so we're more likely to + // see a failure if GL is still texturing from the buffer we + // just dequeued. + for (int j = 0; j < numTestPixels; j++) { + int x = mTestPixels[j].x; + int y = mTestPixels[j].y; + uint8_t value = 128; + img[y*stride + x] = value; + } + + // Fill the buffer with gray. + for (int y = 0; y < texHeight; y++) { + for (int x = 0; x < texWidth; x++) { + img[yuvTexOffsetY + y*yuvTexStrideY + x] = 128; + img[yuvTexOffsetU + (y/2)*yuvTexStrideU + x/2] = 128; + img[yuvTexOffsetV + (y/2)*yuvTexStrideV + x/2] = 128; + } + } + + // Set the test pixels to either white or black. + for (int j = 0; j < numTestPixels; j++) { + int x = mTestPixels[j].x; + int y = mTestPixels[j].y; + uint8_t value = 0; + if (j == (i % numTestPixels)) { + value = 255; + } + img[y*stride + x] = value; + } + + buf->unlock(); + if (mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()) + != NO_ERROR) { + return false; + } + } + return false; + } + + sp<ANativeWindow> mANW; + const TestPixel* mTestPixels; + }; + + sp<FrameWaiter> fw(new FrameWaiter); + mST->setFrameAvailableListener(fw); + + sp<Thread> pt(new ProducerThread(mANW, testPixels)); + pt->run(); + + glViewport(0, 0, texWidth, texHeight); + + glClearColor(0.2, 0.2, 0.2, 0.2); + glClear(GL_COLOR_BUFFER_BIT); + + // We wait for the first two frames up front so that the producer will be + // likely to dequeue the buffer that's currently being textured from. + fw->waitForFrame(); + fw->waitForFrame(); + + for (int i = 0; i < numFrames; i++) { + SCOPED_TRACE(String8::format("frame %d", i).string()); + + // We must wait for each frame to come in because if we ever do an + // updateTexImage call that doesn't consume a newly available buffer + // then the producer and consumer will get out of sync, which will cause + // a deadlock. + if (i > 1) { + fw->waitForFrame(); + } + mST->updateTexImage(); + drawTexture(); + + for (int j = 0; j < numTestPixels; j++) { + int x = testPixels[j].x; + int y = testPixels[j].y; + uint8_t value = 0; + if (j == (i % numTestPixels)) { + // We must y-invert the texture coords + EXPECT_TRUE(checkPixel(x, texHeight-y-1, 255, 255, 255, 255)); + } else { + // We must y-invert the texture coords + EXPECT_TRUE(checkPixel(x, texHeight-y-1, 0, 0, 0, 255)); + } + } + } + + pt->requestExitAndWait(); +} + // XXX: This test is disabled because there are currently no drivers that can // handle RGBA textures with the GL_TEXTURE_EXTERNAL_OES target. TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromCpuFilledRGBABufferNpot) { @@ -1004,8 +1180,7 @@ protected: sp<FrameCondition> mFC; }; -// XXX: This test is disabled because it causes hangs on some devices. -TEST_F(SurfaceTextureGLToGLTest, DISABLED_UpdateTexImageBeforeFrameFinishedWorks) { +TEST_F(SurfaceTextureGLToGLTest, UpdateTexImageBeforeFrameFinishedWorks) { class PT : public ProducerThread { virtual void render() { glClearColor(0.0f, 1.0f, 0.0f, 1.0f); @@ -1023,8 +1198,7 @@ TEST_F(SurfaceTextureGLToGLTest, DISABLED_UpdateTexImageBeforeFrameFinishedWorks // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported! } -// XXX: This test is disabled because it causes hangs on some devices. -TEST_F(SurfaceTextureGLToGLTest, DISABLED_UpdateTexImageAfterFrameFinishedWorks) { +TEST_F(SurfaceTextureGLToGLTest, UpdateTexImageAfterFrameFinishedWorks) { class PT : public ProducerThread { virtual void render() { glClearColor(0.0f, 1.0f, 0.0f, 1.0f); @@ -1042,8 +1216,7 @@ TEST_F(SurfaceTextureGLToGLTest, DISABLED_UpdateTexImageAfterFrameFinishedWorks) // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported! } -// XXX: This test is disabled because it causes hangs on some devices. -TEST_F(SurfaceTextureGLToGLTest, DISABLED_RepeatedUpdateTexImageBeforeFrameFinishedWorks) { +TEST_F(SurfaceTextureGLToGLTest, RepeatedUpdateTexImageBeforeFrameFinishedWorks) { enum { NUM_ITERATIONS = 1024 }; class PT : public ProducerThread { @@ -1071,8 +1244,7 @@ TEST_F(SurfaceTextureGLToGLTest, DISABLED_RepeatedUpdateTexImageBeforeFrameFinis } } -// XXX: This test is disabled because it causes hangs on some devices. -TEST_F(SurfaceTextureGLToGLTest, DISABLED_RepeatedUpdateTexImageAfterFrameFinishedWorks) { +TEST_F(SurfaceTextureGLToGLTest, RepeatedUpdateTexImageAfterFrameFinishedWorks) { enum { NUM_ITERATIONS = 1024 }; class PT : public ProducerThread { diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 35c8640..ce587b3 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -31,15 +31,15 @@ protected: ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); mSurfaceControl = mComposerClient->createSurface( - String8("Test Surface"), 0, 32, 32, PIXEL_FORMAT_RGB_888, 0); + String8("Test Surface"), 0, 32, 32, PIXEL_FORMAT_RGBA_8888, 0); ASSERT_TRUE(mSurfaceControl != NULL); ASSERT_TRUE(mSurfaceControl->isValid()); - ASSERT_EQ(NO_ERROR, mComposerClient->openTransaction()); - ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(30000)); + SurfaceComposerClient::openGlobalTransaction(); + ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7fffffff)); ASSERT_EQ(NO_ERROR, mSurfaceControl->show()); - ASSERT_EQ(NO_ERROR, mComposerClient->closeTransaction()); + SurfaceComposerClient::closeGlobalTransaction(); mSurface = mSurfaceControl->getSurface(); ASSERT_TRUE(mSurface != NULL); @@ -84,7 +84,7 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersFail) { PixelFormat fmt=0; sp<ISurfaceComposer> sf(ComposerService::getComposerService()); ASSERT_EQ(NO_ERROR, sf->captureScreen(0, &heap, &w, &h, &fmt, 64, 64, 0, - 40000)); + 0x7fffffff)); ASSERT_TRUE(heap != NULL); // Set the PROTECTED usage bit and verify that the screenshot fails. Note @@ -94,6 +94,18 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersFail) { GRALLOC_USAGE_PROTECTED)); ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(anw.get(), 3)); ANativeWindowBuffer* buf = 0; + + status_t err = anw->dequeueBuffer(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)); + return; + } + ASSERT_EQ(NO_ERROR, anw->cancelBuffer(anw.get(), buf)); + 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)); @@ -103,7 +115,7 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersFail) { heap = 0; w = h = fmt = 0; ASSERT_EQ(INVALID_OPERATION, sf->captureScreen(0, &heap, &w, &h, &fmt, - 64, 64, 0, 40000)); + 64, 64, 0, 0x7fffffff)); ASSERT_TRUE(heap == NULL); // XXX: This should not be needed, but it seems that the new buffers don't @@ -126,7 +138,7 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersFail) { heap = 0; w = h = fmt = 0; ASSERT_EQ(NO_ERROR, sf->captureScreen(0, &heap, &w, &h, &fmt, 64, 64, 0, - 40000)); + 0x7fffffff)); ASSERT_TRUE(heap != NULL); } diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp index e43f6e5..8b1caeee 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -699,9 +699,10 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) float* vertices = getFloats(verticesCount); bool hasColors = getInt(); int* colors = hasColors ? getInts(colorsCount) : NULL; + SkPaint* paint = getPaint(); DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); - renderer.drawBitmapMesh(bitmap, meshWidth, meshHeight, vertices, colors, getPaint()); + renderer.drawBitmapMesh(bitmap, meshWidth, meshHeight, vertices, colors, paint); } break; case DrawPatch: { @@ -718,9 +719,15 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) yDivs = getInts(yDivsCount); colors = getUInts(numColors); + float left = getFloat(); + float top = getFloat(); + float right = getFloat(); + float bottom = getFloat(); + SkPaint* paint = getPaint(); + DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); renderer.drawPatch(bitmap, xDivs, yDivs, colors, xDivsCount, yDivsCount, - numColors, getFloat(), getFloat(), getFloat(), getFloat(), getPaint()); + numColors, left, top, right, bottom, paint); } break; case DrawColor: { @@ -799,15 +806,17 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) case DrawLines: { int count = 0; float* points = getFloats(count); + SkPaint* paint = getPaint(); DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); - renderer.drawLines(points, count, getPaint()); + renderer.drawLines(points, count, paint); } break; case DrawPoints: { int count = 0; float* points = getFloats(count); + SkPaint* paint = getPaint(); DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); - renderer.drawPoints(points, count, getPaint()); + renderer.drawPoints(points, count, paint); } break; case DrawText: { diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index 0310bc3..3c2d80d 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -27,6 +27,7 @@ #include "Rect.h" #include "SkiaColorFilter.h" +#include "Texture.h" #include "Vertex.h" namespace android { @@ -40,14 +41,18 @@ namespace uirenderer { * A layer has dimensions and is backed by an OpenGL texture or FBO. */ struct Layer { - Layer(const uint32_t layerWidth, const uint32_t layerHeight): - width(layerWidth), height(layerHeight) { + Layer(const uint32_t layerWidth, const uint32_t layerHeight) { mesh = NULL; meshIndices = NULL; meshElementCount = 0; - isCacheable = true; - isTextureLayer = false; + cacheable = true; + textureLayer = false; renderTarget = GL_TEXTURE_2D; + texture.width = layerWidth; + texture.height = layerHeight; + colorFilter = NULL; + firstFilter = true; + firstWrap = true; } ~Layer() { @@ -64,12 +69,152 @@ struct Layer { regionRect.set(bounds.leftTop().x, bounds.leftTop().y, bounds.rightBottom().x, bounds.rightBottom().y); - const float texX = 1.0f / float(width); - const float texY = 1.0f / float(height); + const float texX = 1.0f / float(texture.width); + const float texY = 1.0f / float(texture.height); const float height = layer.getHeight(); texCoords.set( regionRect.left * texX, (height - regionRect.top) * texY, regionRect.right * texX, (height - regionRect.bottom) * texY); + + regionRect.translate(layer.left, layer.top); + } + + inline uint32_t getWidth() { + return texture.width; + } + + inline uint32_t getHeight() { + return texture.height; + } + + void setSize(uint32_t width, uint32_t height) { + texture.width = width; + texture.height = height; + } + + inline void setBlend(bool blend) { + texture.blend = blend; + } + + inline bool isBlend() { + return texture.blend; + } + + inline void setAlpha(int alpha) { + this->alpha = alpha; + } + + inline void setAlpha(int alpha, SkXfermode::Mode mode) { + this->alpha = alpha; + this->mode = mode; + } + + inline int getAlpha() { + return alpha; + } + + inline SkXfermode::Mode getMode() { + return mode; + } + + inline void setEmpty(bool empty) { + this->empty = empty; + } + + inline bool isEmpty() { + return empty; + } + + inline void setFbo(GLuint fbo) { + this->fbo = fbo; + } + + inline GLuint getFbo() { + return fbo; + } + + inline GLuint* getTexturePointer() { + return &texture.id; + } + + inline GLuint getTexture() { + return texture.id; + } + + inline GLenum getRenderTarget() { + return renderTarget; + } + + inline void setRenderTarget(GLenum renderTarget) { + this->renderTarget = renderTarget; + } + + void setWrap(GLenum wrapS, GLenum wrapT, bool bindTexture = false, bool force = false) { + if (firstWrap || force || wrapS != texture.wrapS || wrapT != texture.wrapT) { + firstWrap = true; + texture.setWrap(wrapS, wrapT); + if (bindTexture) { + glBindTexture(renderTarget, texture.id); + } + glTexParameteri(renderTarget, GL_TEXTURE_WRAP_S, wrapS); + glTexParameteri(renderTarget, GL_TEXTURE_WRAP_T, wrapT); + } + } + + void setFilter(GLenum min, GLenum mag, bool bindTexture = false, bool force = false) { + if (firstFilter || force || min != texture.minFilter || mag != texture.magFilter) { + firstFilter = false; + texture.setFilter(min, mag); + if (bindTexture) { + glBindTexture(renderTarget, texture.id); + } + glTexParameteri(renderTarget, GL_TEXTURE_MIN_FILTER, min); + glTexParameteri(renderTarget, GL_TEXTURE_MAG_FILTER, mag); + } + } + + inline bool isCacheable() { + return cacheable; + } + + inline void setCacheable(bool cacheable) { + this->cacheable = cacheable; + } + + inline bool isTextureLayer() { + return textureLayer; + } + + inline void setTextureLayer(bool textureLayer) { + this->textureLayer = textureLayer; + } + + inline SkiaColorFilter* getColorFilter() { + return colorFilter; + } + + inline void setColorFilter(SkiaColorFilter* filter) { + colorFilter = filter; + } + + inline void bindTexture() { + glBindTexture(renderTarget, texture.id); + } + + inline void generateTexture() { + glGenTextures(1, &texture.id); + } + + inline void deleteTexture() { + if (texture.id) glDeleteTextures(1, &texture.id); + } + + inline void allocateTexture(GLenum format, GLenum storage) { + glTexImage2D(renderTarget, 0, format, getWidth(), getHeight(), 0, format, storage, NULL); + } + + inline mat4& getTexTransform() { + return texTransform; } /** @@ -82,23 +227,29 @@ struct Layer { Rect texCoords; /** - * Name of the FBO used to render the layer. If the name is 0 - * this layer is not backed by an FBO, but a simple texture. + * Dirty region indicating what parts of the layer + * have been drawn. */ - GLuint fbo; - + Region region; /** - * Opacity of the layer. + * If the region is a rectangle, coordinates of the + * region are stored here. */ - int alpha; + Rect regionRect; + /** - * Blending mode of the layer. + * If the layer can be rendered as a mesh, this is non-null. */ - SkXfermode::Mode mode; + TextureVertex* mesh; + uint16_t* meshIndices; + GLsizei meshElementCount; + +private: /** - * Indicates whether this layer should be blended. + * Name of the FBO used to render the layer. If the name is 0 + * this layer is not backed by an FBO, but a simple texture. */ - bool blend; + GLuint fbo; /** * Indicates whether this layer has been used already. @@ -106,28 +257,25 @@ struct Layer { bool empty; /** - * Name of the texture used to render the layer. - */ - GLuint texture; - /** - * Width of the layer texture. + * The texture backing this layer. */ - uint32_t width; + Texture texture; + /** - * Height of the layer texture. + * If set to true (by default), the layer can be reused. */ - uint32_t height; + bool cacheable; /** - * Dirty region indicating what parts of the layer - * have been drawn. + * When set to true, this layer must be treated as a texture + * layer. */ - Region region; + bool textureLayer; + /** - * If the region is a rectangle, coordinates of the - * region are stored here. + * Indicates the render target. */ - Rect regionRect; + GLenum renderTarget; /** * Color filter used to draw this layer. Optional. @@ -135,32 +283,21 @@ struct Layer { SkiaColorFilter* colorFilter; /** - * If the layer can be rendered as a mesh, this is non-null. - */ - TextureVertex* mesh; - uint16_t* meshIndices; - GLsizei meshElementCount; - - /** - * If set to true (by default), the layer can be reused. + * Opacity of the layer. */ - bool isCacheable; - + int alpha; /** - * When set to true, this layer must be treated as a texture - * layer. + * Blending mode of the layer. */ - bool isTextureLayer; + SkXfermode::Mode mode; /** * Optional texture coordinates transform. */ mat4 texTransform; - /** - * Indicates the render target. - */ - GLenum renderTarget; + bool firstFilter; + bool firstWrap; }; // struct Layer }; // namespace uirenderer diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp index b2d795f..1a15e87 100644 --- a/libs/hwui/LayerCache.cpp +++ b/libs/hwui/LayerCache.cpp @@ -68,8 +68,8 @@ void LayerCache::setMaxSize(uint32_t maxSize) { void LayerCache::deleteLayer(Layer* layer) { if (layer) { - mSize -= layer->width * layer->height * 4; - glDeleteTextures(1, &layer->texture); + mSize -= layer->getWidth() * layer->getHeight() * 4; + layer->deleteTexture(); delete layer; } } @@ -93,29 +93,23 @@ Layer* LayerCache::get(const uint32_t width, const uint32_t height) { mCache.removeAt(index); layer = entry.mLayer; - mSize -= layer->width * layer->height * 4; + mSize -= layer->getWidth() * layer->getHeight() * 4; - LAYER_LOGD("Reusing layer %dx%d", layer->width, layer->height); + LAYER_LOGD("Reusing layer %dx%d", layer->getWidth(), layer->getHeight()); } else { LAYER_LOGD("Creating new layer %dx%d", entry.mWidth, entry.mHeight); layer = new Layer(entry.mWidth, entry.mHeight); - layer->blend = true; - layer->empty = true; - layer->fbo = 0; - layer->colorFilter = NULL; - - glGenTextures(1, &layer->texture); - glBindTexture(GL_TEXTURE_2D, layer->texture); - + layer->setBlend(true); + layer->setEmpty(true); + layer->setFbo(0); + + layer->generateTexture(); + layer->bindTexture(); + layer->setFilter(GL_NEAREST, GL_NEAREST); + layer->setWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - #if DEBUG_LAYERS size_t size = mCache.size(); for (size_t i = 0; i < size; i++) { @@ -133,30 +127,30 @@ bool LayerCache::resize(Layer* layer, const uint32_t width, const uint32_t heigh // size already in the cache, and reuse it instead of creating a new one LayerEntry entry(width, height); - if (entry.mWidth <= layer->width && entry.mHeight <= layer->height) { + if (entry.mWidth <= layer->getWidth() && entry.mHeight <= layer->getHeight()) { return true; } - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, layer->texture); + uint32_t oldWidth = layer->getWidth(); + uint32_t oldHeight = layer->getHeight(); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, entry.mWidth, entry.mHeight, 0, - GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glActiveTexture(GL_TEXTURE0); + layer->bindTexture(); + layer->setSize(entry.mWidth, entry.mHeight); + layer->allocateTexture(GL_RGBA, GL_UNSIGNED_BYTE); if (glGetError() != GL_NO_ERROR) { + layer->setSize(oldWidth, oldHeight); return false; } - layer->width = entry.mWidth; - layer->height = entry.mHeight; - return true; } bool LayerCache::put(Layer* layer) { - if (!layer->isCacheable) return false; + if (!layer->isCacheable()) return false; - const uint32_t size = layer->width * layer->height * 4; + const uint32_t size = layer->getWidth() * layer->getHeight() * 4; // Don't even try to cache a layer that's bigger than the cache if (size < mMaxSize) { // TODO: Use an LRU diff --git a/libs/hwui/LayerCache.h b/libs/hwui/LayerCache.h index d2d5f39..81b8bf3 100644 --- a/libs/hwui/LayerCache.h +++ b/libs/hwui/LayerCache.h @@ -119,7 +119,7 @@ private: } LayerEntry(Layer* layer): - mLayer(layer), mWidth(layer->width), mHeight(layer->height) { + mLayer(layer), mWidth(layer->getWidth()), mHeight(layer->getHeight()) { } bool operator<(const LayerEntry& rhs) const { diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp index dfb5d3b..1fa343b 100644 --- a/libs/hwui/LayerRenderer.cpp +++ b/libs/hwui/LayerRenderer.cpp @@ -32,9 +32,9 @@ namespace uirenderer { /////////////////////////////////////////////////////////////////////////////// void LayerRenderer::prepareDirty(float left, float top, float right, float bottom, bool opaque) { - LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->fbo); + LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->getFbo()); - glBindFramebuffer(GL_FRAMEBUFFER, mLayer->fbo); + glBindFramebuffer(GL_FRAMEBUFFER, mLayer->getFbo()); const float width = mLayer->layer.getWidth(); const float height = mLayer->layer.getHeight(); @@ -62,14 +62,14 @@ void LayerRenderer::finish() { generateMesh(); - LAYER_RENDERER_LOGD("Finished rendering into layer, fbo = %d", mLayer->fbo); + LAYER_RENDERER_LOGD("Finished rendering into layer, fbo = %d", mLayer->getFbo()); // No need to unbind our FBO, this will be taken care of by the caller // who will invoke OpenGLRenderer::resume() } GLint LayerRenderer::getTargetFbo() { - return mLayer->fbo; + return mLayer->getFbo(); } /////////////////////////////////////////////////////////////////////////////// @@ -128,8 +128,8 @@ void LayerRenderer::generateMesh() { } mLayer->meshElementCount = elementCount; - const float texX = 1.0f / float(mLayer->width); - const float texY = 1.0f / float(mLayer->height); + const float texX = 1.0f / float(mLayer->getWidth()); + const float texY = 1.0f / float(mLayer->getHeight()); const float height = mLayer->layer.getHeight(); TextureVertex* mesh = mLayer->mesh; @@ -166,30 +166,6 @@ void LayerRenderer::generateMesh() { // Layers management /////////////////////////////////////////////////////////////////////////////// -Layer* LayerRenderer::createTextureLayer(bool isOpaque) { - LAYER_RENDERER_LOGD("Creating new texture layer"); - - Layer* layer = new Layer(0, 0); - layer->isCacheable = false; - layer->isTextureLayer = true; - layer->blend = !isOpaque; - layer->empty = true; - layer->fbo = 0; - layer->colorFilter = NULL; - layer->fbo = 0; - layer->layer.set(0.0f, 0.0f, 0.0f, 0.0f); - layer->texCoords.set(0.0f, 1.0f, 0.0f, 1.0f); - layer->alpha = 255; - layer->mode = SkXfermode::kSrcOver_Mode; - layer->colorFilter = NULL; - layer->region.clear(); - - glActiveTexture(GL_TEXTURE0); - glGenTextures(1, &layer->texture); - - return layer; -} - Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque) { LAYER_RENDERER_LOGD("Creating new layer %dx%d", width, height); @@ -206,40 +182,41 @@ Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque return NULL; } - layer->fbo = fbo; + layer->setFbo(fbo); layer->layer.set(0.0f, 0.0f, width, height); - layer->texCoords.set(0.0f, height / float(layer->height), - width / float(layer->width), 0.0f); - layer->alpha = 255; - layer->mode = SkXfermode::kSrcOver_Mode; - layer->blend = !isOpaque; - layer->colorFilter = NULL; + layer->texCoords.set(0.0f, height / float(layer->getHeight()), + width / float(layer->getWidth()), 0.0f); + layer->setAlpha(255, SkXfermode::kSrcOver_Mode); + layer->setBlend(!isOpaque); + layer->setColorFilter(NULL); layer->region.clear(); GLuint previousFbo; glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo); - glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo); - glBindTexture(GL_TEXTURE_2D, layer->texture); + glBindFramebuffer(GL_FRAMEBUFFER, layer->getFbo()); + layer->bindTexture(); // Initialize the texture if needed - if (layer->empty) { - layer->empty = false; - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layer->width, layer->height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, NULL); + if (layer->isEmpty()) { + layer->setEmpty(false); + layer->allocateTexture(GL_RGBA, GL_UNSIGNED_BYTE); if (glGetError() != GL_NO_ERROR) { LOGD("Could not allocate texture"); + glBindFramebuffer(GL_FRAMEBUFFER, previousFbo); - glDeleteTextures(1, &layer->texture); Caches::getInstance().fboCache.put(fbo); + + layer->deleteTexture(); delete layer; + return NULL; } } glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - layer->texture, 0); + layer->getTexture(), 0); glDisable(GL_SCISSOR_TEST); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); @@ -253,14 +230,14 @@ Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque bool LayerRenderer::resizeLayer(Layer* layer, uint32_t width, uint32_t height) { if (layer) { - LAYER_RENDERER_LOGD("Resizing layer fbo = %d to %dx%d", layer->fbo, width, height); + LAYER_RENDERER_LOGD("Resizing layer fbo = %d to %dx%d", layer->getFbo(), width, height); if (Caches::getInstance().layerCache.resize(layer, width, height)) { layer->layer.set(0.0f, 0.0f, width, height); - layer->texCoords.set(0.0f, height / float(layer->height), - width / float(layer->width), 0.0f); + layer->texCoords.set(0.0f, height / float(layer->getHeight()), + width / float(layer->getWidth()), 0.0f); } else { - if (layer->texture) glDeleteTextures(1, &layer->texture); + layer->deleteTexture(); delete layer; return false; } @@ -269,38 +246,56 @@ bool LayerRenderer::resizeLayer(Layer* layer, uint32_t width, uint32_t height) { return true; } +Layer* LayerRenderer::createTextureLayer(bool isOpaque) { + LAYER_RENDERER_LOGD("Creating new texture layer"); + + Layer* layer = new Layer(0, 0); + layer->setCacheable(false); + layer->setTextureLayer(true); + layer->setBlend(!isOpaque); + layer->setEmpty(true); + layer->setFbo(0); + layer->setAlpha(255, SkXfermode::kSrcOver_Mode); + layer->layer.set(0.0f, 0.0f, 0.0f, 0.0f); + layer->texCoords.set(0.0f, 1.0f, 0.0f, 1.0f); + layer->region.clear(); + layer->setRenderTarget(GL_NONE); // see ::updateTextureLayer() + + glActiveTexture(GL_TEXTURE0); + layer->generateTexture(); + + return layer; +} + void LayerRenderer::updateTextureLayer(Layer* layer, uint32_t width, uint32_t height, bool isOpaque, GLenum renderTarget, float* transform) { if (layer) { - layer->blend = !isOpaque; - layer->width = width; - layer->height = height; + layer->setBlend(!isOpaque); + layer->setSize(width, height); layer->layer.set(0.0f, 0.0f, width, height); layer->region.set(width, height); layer->regionRect.set(0.0f, 0.0f, width, height); - layer->texTransform.load(transform); - layer->renderTarget = renderTarget; - - glBindTexture(layer->renderTarget, layer->texture); + layer->getTexTransform().load(transform); - glTexParameteri(layer->renderTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(layer->renderTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - glTexParameteri(layer->renderTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(layer->renderTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + if (renderTarget != layer->getRenderTarget()) { + layer->setRenderTarget(renderTarget); + layer->bindTexture(); + layer->setFilter(GL_NEAREST, GL_NEAREST, false, true); + layer->setWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, false, true); + } } } void LayerRenderer::destroyLayer(Layer* layer) { if (layer) { - LAYER_RENDERER_LOGD("Destroying layer, fbo = %d", layer->fbo); + LAYER_RENDERER_LOGD("Destroying layer, fbo = %d", layer->getFbo()); - if (layer->fbo) { - Caches::getInstance().fboCache.put(layer->fbo); + if (layer->getFbo()) { + Caches::getInstance().fboCache.put(layer->getFbo()); } if (!Caches::getInstance().layerCache.put(layer)) { - if (layer->texture) glDeleteTextures(1, &layer->texture); + layer->deleteTexture(); delete layer; } else { layer->region.clear(); @@ -310,7 +305,7 @@ void LayerRenderer::destroyLayer(Layer* layer) { void LayerRenderer::destroyLayerDeferred(Layer* layer) { if (layer) { - LAYER_RENDERER_LOGD("Deferring layer destruction, fbo = %d", layer->fbo); + LAYER_RENDERER_LOGD("Deferring layer destruction, fbo = %d", layer->getFbo()); Caches::getInstance().deleteLayerDeferred(layer); } @@ -318,7 +313,7 @@ void LayerRenderer::destroyLayerDeferred(Layer* layer) { bool LayerRenderer::copyLayer(Layer* layer, SkBitmap* bitmap) { Caches& caches = Caches::getInstance(); - if (layer && layer->isTextureLayer && bitmap->width() <= caches.maxTextureSize && + if (layer && layer->isTextureLayer() && bitmap->width() <= caches.maxTextureSize && bitmap->height() <= caches.maxTextureSize) { GLuint fbo = caches.fboCache.get(); @@ -358,12 +353,11 @@ bool LayerRenderer::copyLayer(Layer* layer, SkBitmap* bitmap) { break; } - float alpha = layer->alpha; - SkXfermode::Mode mode = layer->mode; + float alpha = layer->getAlpha(); + SkXfermode::Mode mode = layer->getMode(); - layer->mode = SkXfermode::kSrc_Mode; - layer->alpha = 255; - layer->fbo = fbo; + layer->setAlpha(255, SkXfermode::kSrc_Mode); + layer->setFbo(fbo); glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo); @@ -374,8 +368,8 @@ bool LayerRenderer::copyLayer(Layer* layer, SkBitmap* bitmap) { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); @@ -392,7 +386,7 @@ bool LayerRenderer::copyLayer(Layer* layer, SkBitmap* bitmap) { LayerRenderer renderer(layer); renderer.setViewport(bitmap->width(), bitmap->height()); renderer.OpenGLRenderer::prepareDirty(0.0f, 0.0f, - bitmap->width(), bitmap->height(), !layer->blend); + bitmap->width(), bitmap->height(), !layer->isBlend()); if ((error = glGetError()) != GL_NO_ERROR) goto error; { @@ -417,9 +411,8 @@ error: #endif glBindFramebuffer(GL_FRAMEBUFFER, previousFbo); - layer->mode = mode; - layer->alpha = alpha; - layer->fbo = 0; + layer->setAlpha(alpha, mode); + layer->setFbo(0); glDeleteTextures(1, &texture); caches.fboCache.put(fbo); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 1c06a0b..a349121 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -449,12 +449,11 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top, return false; } - layer->mode = mode; - layer->alpha = alpha; + layer->setAlpha(alpha, mode); layer->layer.set(bounds); - layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->height), - bounds.getWidth() / float(layer->width), 0.0f); - layer->colorFilter = mColorFilter; + layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->getHeight()), + bounds.getWidth() / float(layer->getWidth()), 0.0f); + layer->setColorFilter(mColorFilter); // Save the layer in the snapshot snapshot->flags |= Snapshot::kFlagIsLayer; @@ -464,12 +463,13 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top, return createFboLayer(layer, bounds, snapshot, previousFbo); } else { // Copy the framebuffer into the layer - glBindTexture(GL_TEXTURE_2D, layer->texture); + layer->bindTexture(); if (!bounds.isEmpty()) { - if (layer->empty) { - glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bounds.left, - snapshot->height - bounds.bottom, layer->width, layer->height, 0); - layer->empty = false; + if (layer->isEmpty()) { + glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, + bounds.left, snapshot->height - bounds.bottom, + layer->getWidth(), layer->getHeight(), 0); + layer->setEmpty(false); } else { glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left, snapshot->height - bounds.bottom, bounds.getWidth(), bounds.getHeight()); @@ -485,7 +485,7 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top, bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, sp<Snapshot> snapshot, GLuint previousFbo) { - layer->fbo = mCaches.fboCache.get(); + layer->setFbo(mCaches.fboCache.get()); #if RENDER_LAYERS_AS_REGIONS snapshot->region = &snapshot->layer->region; @@ -507,7 +507,7 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, sp<Snapshot> sna clip.translate(-bounds.left, -bounds.top); snapshot->flags |= Snapshot::kFlagIsFboLayer; - snapshot->fbo = layer->fbo; + snapshot->fbo = layer->getFbo(); snapshot->resetTransform(-bounds.left, -bounds.top, 0.0f); snapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom); snapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight()); @@ -516,18 +516,17 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, sp<Snapshot> sna snapshot->orthoMatrix.load(mOrthoMatrix); // Bind texture to FBO - glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo); - glBindTexture(GL_TEXTURE_2D, layer->texture); + glBindFramebuffer(GL_FRAMEBUFFER, layer->getFbo()); + layer->bindTexture(); // Initialize the texture if needed - if (layer->empty) { - layer->empty = false; - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layer->width, layer->height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, NULL); + if (layer->isEmpty()) { + layer->allocateTexture(GL_RGBA, GL_UNSIGNED_BYTE); + layer->setEmpty(false); } glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - layer->texture, 0); + layer->getTexture(), 0); #if DEBUG_LAYERS_AS_REGIONS GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); @@ -535,8 +534,8 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, sp<Snapshot> sna LOGE("Framebuffer incomplete (GL error code 0x%x)", status); glBindFramebuffer(GL_FRAMEBUFFER, previousFbo); - glDeleteTextures(1, &layer->texture); - mCaches.fboCache.put(layer->fbo); + layer->deleteTexture(); + mCaches.fboCache.put(layer->getFbo()); delete layer; @@ -578,11 +577,11 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) { Layer* layer = current->layer; const Rect& rect = layer->layer; - if (!fboLayer && layer->alpha < 255) { + if (!fboLayer && layer->getAlpha() < 255) { drawColorRect(rect.left, rect.top, rect.right, rect.bottom, - layer->alpha << 24, SkXfermode::kDstIn_Mode, true); + layer->getAlpha() << 24, SkXfermode::kDstIn_Mode, true); // Required below, composeLayerRect() will divide by 255 - layer->alpha = 255; + layer->setAlpha(255); } mCaches.unbindMeshBuffer(); @@ -593,18 +592,16 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) { // drawing only the dirty region if (fboLayer) { dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *previous->transform); - if (layer->colorFilter) { - setupColorFilter(layer->colorFilter); + if (layer->getColorFilter()) { + setupColorFilter(layer->getColorFilter()); } composeLayerRegion(layer, rect); - if (layer->colorFilter) { + if (layer->getColorFilter()) { resetColorFilter(); } - } else { - if (!rect.isEmpty()) { - dirtyLayer(rect.left, rect.top, rect.right, rect.bottom); - composeLayerRect(layer, rect, true); - } + } else if (!rect.isEmpty()) { + dirtyLayer(rect.left, rect.top, rect.right, rect.bottom); + composeLayerRect(layer, rect, true); } if (fboLayer) { @@ -622,16 +619,16 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) { // Failing to add the layer to the cache should happen only if the layer is too large if (!mCaches.layerCache.put(layer)) { LAYER_LOGD("Deleting layer"); - glDeleteTextures(1, &layer->texture); + layer->deleteTexture(); delete layer; } } void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) { - float alpha = layer->alpha / 255.0f; + float alpha = layer->getAlpha() / 255.0f; setupDraw(); - if (layer->renderTarget == GL_TEXTURE_2D) { + if (layer->getRenderTarget() == GL_TEXTURE_2D) { setupDrawWithTexture(); } else { setupDrawWithExternalTexture(); @@ -639,17 +636,28 @@ void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) { setupDrawTextureTransform(); setupDrawColor(alpha, alpha, alpha, alpha); setupDrawColorFilter(); - setupDrawBlending(layer->blend || layer->alpha < 255, layer->mode); + setupDrawBlending(layer->isBlend() || alpha < 1.0f, layer->getMode()); setupDrawProgram(); - setupDrawModelView(rect.left, rect.top, rect.right, rect.bottom); setupDrawPureColorUniforms(); setupDrawColorFilterUniforms(); - if (layer->renderTarget == GL_TEXTURE_2D) { - setupDrawTexture(layer->texture); + if (layer->getRenderTarget() == GL_TEXTURE_2D) { + setupDrawTexture(layer->getTexture()); + } else { + setupDrawExternalTexture(layer->getTexture()); + } + if (mSnapshot->transform->isPureTranslate() && + layer->getWidth() == (uint32_t) rect.getWidth() && + layer->getHeight() == (uint32_t) rect.getHeight()) { + const float x = (int) floorf(rect.left + mSnapshot->transform->getTranslateX() + 0.5f); + const float y = (int) floorf(rect.top + mSnapshot->transform->getTranslateY() + 0.5f); + + layer->setFilter(GL_NEAREST, GL_NEAREST); + setupDrawModelView(x, y, x + rect.getWidth(), y + rect.getHeight(), true); } else { - setupDrawExternalTexture(layer->texture); + layer->setFilter(GL_LINEAR, GL_LINEAR); + setupDrawModelView(rect.left, rect.top, rect.right, rect.bottom); } - setupDrawTextureTransformUniforms(layer->texTransform); + setupDrawTextureTransformUniforms(layer->getTexTransform()); setupDrawMesh(&mMeshVertices[0].position[0], &mMeshVertices[0].texture[0]); glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); @@ -658,14 +666,34 @@ void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) { } void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) { - if (!layer->isTextureLayer) { + if (!layer->isTextureLayer()) { const Rect& texCoords = layer->texCoords; resetDrawTextureTexCoords(texCoords.left, texCoords.top, texCoords.right, texCoords.bottom); - drawTextureMesh(rect.left, rect.top, rect.right, rect.bottom, layer->texture, - layer->alpha / 255.0f, layer->mode, layer->blend, &mMeshVertices[0].position[0], - &mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount, swap, swap); + float x = rect.left; + float y = rect.top; + bool simpleTransform = mSnapshot->transform->isPureTranslate() && + layer->getWidth() == (uint32_t) rect.getWidth() && + layer->getHeight() == (uint32_t) rect.getHeight(); + + if (simpleTransform) { + // When we're swapping, the layer is already in screen coordinates + if (!swap) { + x = (int) floorf(rect.left + mSnapshot->transform->getTranslateX() + 0.5f); + y = (int) floorf(rect.top + mSnapshot->transform->getTranslateY() + 0.5f); + } + + layer->setFilter(GL_NEAREST, GL_NEAREST, true); + } else { + layer->setFilter(GL_LINEAR, GL_LINEAR, true); + } + + drawTextureMesh(x, y, x + rect.getWidth(), y + rect.getHeight(), + layer->getTexture(), layer->getAlpha() / 255.0f, + layer->getMode(), layer->isBlend(), + &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], + GL_TRIANGLE_STRIP, gMeshCount, swap, swap || simpleTransform); resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); } else { @@ -690,9 +718,9 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { size_t count; const android::Rect* rects = layer->region.getArray(&count); - const float alpha = layer->alpha / 255.0f; - const float texX = 1.0f / float(layer->width); - const float texY = 1.0f / float(layer->height); + const float alpha = layer->getAlpha() / 255.0f; + const float texX = 1.0f / float(layer->getWidth()); + const float texY = 1.0f / float(layer->getHeight()); const float height = rect.getHeight(); TextureVertex* mesh = mCaches.getRegionMesh(); @@ -702,13 +730,22 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { setupDrawWithTexture(); setupDrawColor(alpha, alpha, alpha, alpha); setupDrawColorFilter(); - setupDrawBlending(layer->blend || layer->alpha < 255, layer->mode, false); + setupDrawBlending(layer->isBlend() || alpha < 1.0f, layer->getMode(), false); setupDrawProgram(); setupDrawDirtyRegionsDisabled(); setupDrawPureColorUniforms(); setupDrawColorFilterUniforms(); - setupDrawTexture(layer->texture); - setupDrawModelViewTranslate(rect.left, rect.top, rect.right, rect.bottom); + setupDrawTexture(layer->getTexture()); + if (mSnapshot->transform->isPureTranslate()) { + const float x = (int) floorf(rect.left + mSnapshot->transform->getTranslateX() + 0.5f); + const float y = (int) floorf(rect.top + mSnapshot->transform->getTranslateY() + 0.5f); + + layer->setFilter(GL_NEAREST, GL_NEAREST); + setupDrawModelViewTranslate(x, y, x + rect.getWidth(), y + rect.getHeight(), true); + } else { + layer->setFilter(GL_LINEAR, GL_LINEAR); + setupDrawModelViewTranslate(rect.left, rect.top, rect.right, rect.bottom); + } setupDrawMesh(&mesh[0].position[0], &mesh[0].texture[0]); for (size_t i = 0; i < count; i++) { @@ -2154,8 +2191,7 @@ void OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) { SkXfermode::Mode mode; getAlphaAndMode(paint, &alpha, &mode); - layer->alpha = alpha; - layer->mode = mode; + layer->setAlpha(alpha, mode); #if RENDER_LAYERS_AS_REGIONS if (!layer->region.isEmpty()) { @@ -2169,13 +2205,23 @@ void OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) { setupDrawWithTexture(); setupDrawColor(a, a, a, a); setupDrawColorFilter(); - setupDrawBlending(layer->blend || layer->alpha < 255, layer->mode, false); + setupDrawBlending(layer->isBlend() || a < 1.0f, layer->getMode(), false); setupDrawProgram(); - setupDrawModelViewTranslate(x, y, - x + layer->layer.getWidth(), y + layer->layer.getHeight()); setupDrawPureColorUniforms(); setupDrawColorFilterUniforms(); - setupDrawTexture(layer->texture); + setupDrawTexture(layer->getTexture()); + if (mSnapshot->transform->isPureTranslate()) { + x = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f); + y = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f); + + layer->setFilter(GL_NEAREST, GL_NEAREST); + setupDrawModelViewTranslate(x, y, + x + layer->layer.getWidth(), y + layer->layer.getHeight(), true); + } else { + layer->setFilter(GL_LINEAR, GL_LINEAR); + setupDrawModelViewTranslate(x, y, + x + layer->layer.getWidth(), y + layer->layer.getHeight()); + } setupDrawMesh(&layer->mesh[0].position[0], &layer->mesh[0].texture[0]); glDrawElements(GL_TRIANGLES, layer->meshElementCount, diff --git a/libs/hwui/ShapeCache.h b/libs/hwui/ShapeCache.h index b048469..f4d9686 100644 --- a/libs/hwui/ShapeCache.h +++ b/libs/hwui/ShapeCache.h @@ -537,7 +537,7 @@ PathTexture* ShapeCache<Entry>::addTexture(const Entry& entry, const SkPath *pat const float pathWidth = fmax(bounds.width(), 1.0f); const float pathHeight = fmax(bounds.height(), 1.0f); - const float offset = fmax(paint->getStrokeWidth(), 1.0f) * 1.5f; + const float offset = (int) floorf(fmax(paint->getStrokeWidth(), 1.0f) * 1.5f + 0.5f); const uint32_t width = uint32_t(pathWidth + offset * 2.0 + 0.5); const uint32_t height = uint32_t(pathHeight + offset * 2.0 + 0.5); diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h index 4922bb3..c6ae326 100644 --- a/libs/hwui/Texture.h +++ b/libs/hwui/Texture.h @@ -29,8 +29,22 @@ struct Texture { Texture() { cleanup = false; bitmapSize = 0; + wrapS = GL_CLAMP_TO_EDGE; wrapT = GL_CLAMP_TO_EDGE; + + minFilter = GL_NEAREST; + magFilter = GL_NEAREST; + } + + void setWrap(GLenum wrapS, GLenum wrapT) { + this->wrapS = wrapS; + this->wrapT = wrapT; + } + + void setFilter(GLenum min, GLenum mag) { + minFilter = min; + magFilter = mag; } /** @@ -67,6 +81,12 @@ struct Texture { */ GLenum wrapS; GLenum wrapT; + + /** + * Last filters set on this texture. Defaults to GL_NEAREST. + */ + GLenum minFilter; + GLenum magFilter; }; // struct Texture class AutoTexture { diff --git a/libs/rs/driver/rsdBcc.cpp b/libs/rs/driver/rsdBcc.cpp index 8120864..62eb24e 100644 --- a/libs/rs/driver/rsdBcc.cpp +++ b/libs/rs/driver/rsdBcc.cpp @@ -66,65 +66,6 @@ static Script * setTLS(Script *sc) { } -// Input: cacheDir -// Input: resName -// Input: extName -// -// Note: cacheFile = resName + extName -// -// Output: Returns cachePath == cacheDir + cacheFile -static char *genCacheFileName(const char *cacheDir, - const char *resName, - const char *extName) { - char cachePath[512]; - char cacheFile[sizeof(cachePath)]; - const size_t kBufLen = sizeof(cachePath) - 1; - - cacheFile[0] = '\0'; - // Note: resName today is usually something like - // "/com.android.fountain:raw/fountain" - if (resName[0] != '/') { - // Get the absolute path of the raw/***.bc file. - - // Generate the absolute path. This doesn't do everything it - // should, e.g. if resName is "./out/whatever" it doesn't crunch - // the leading "./" out because this if-block is not triggered, - // but it'll make do. - // - if (getcwd(cacheFile, kBufLen) == NULL) { - LOGE("Can't get CWD while opening raw/***.bc file\n"); - return NULL; - } - // Append "/" at the end of cacheFile so far. - strncat(cacheFile, "/", kBufLen); - } - - // cacheFile = resName + extName - // - strncat(cacheFile, resName, kBufLen); - if (extName != NULL) { - // TODO(srhines): strncat() is a bit dangerous - strncat(cacheFile, extName, kBufLen); - } - - // Turn the path into a flat filename by replacing - // any slashes after the first one with '@' characters. - char *cp = cacheFile + 1; - while (*cp != '\0') { - if (*cp == '/') { - *cp = '@'; - } - cp++; - } - - // Tack on the file name for the actual cache file path. - strncpy(cachePath, cacheDir, kBufLen); - strncat(cachePath, cacheFile, kBufLen); - - LOGV("Cache file for '%s' '%s' is '%s'\n", resName, extName, cachePath); - return strdup(cachePath); -} - bool rsdScriptInit(const Context *rsc, ScriptC *script, char const *resName, @@ -164,15 +105,12 @@ bool rsdScriptInit(const Context *rsc, goto error; } -#if 1 if (bccLinkFile(drv->mBccScript, "/system/lib/libclcore.bc", 0) != 0) { LOGE("bcc: FAILS to link bitcode"); goto error; } -#endif - cachePath = genCacheFileName(cacheDir, resName, ".oBCC"); - if (bccPrepareExecutable(drv->mBccScript, cachePath, 0) != 0) { + if (bccPrepareExecutableEx(drv->mBccScript, cacheDir, resName, 0) != 0) { LOGE("bcc: FAILS to prepare executable"); goto error; } @@ -214,14 +152,13 @@ bool rsdScriptInit(const Context *rsc, const char ** mPragmaKeys; const char ** mPragmaValues; - const static int pragmaMax = 16; drv->mPragmaCount = bccGetPragmaCount(drv->mBccScript); if (drv->mPragmaCount <= 0) { drv->mPragmaKeys = NULL; drv->mPragmaValues = NULL; } else { - drv->mPragmaKeys = (const char **) calloc(drv->mFieldCount, sizeof(const char *)); - drv->mPragmaValues = (const char **) calloc(drv->mFieldCount, sizeof(const char *)); + drv->mPragmaKeys = (const char **) calloc(drv->mPragmaCount, sizeof(const char *)); + drv->mPragmaValues = (const char **) calloc(drv->mPragmaCount, sizeof(const char *)); bccGetPragmaList(drv->mBccScript, drv->mPragmaCount, drv->mPragmaKeys, drv->mPragmaValues); } diff --git a/libs/rs/driver/rsdGL.cpp b/libs/rs/driver/rsdGL.cpp index 1f7bb0f..04446ad 100644 --- a/libs/rs/driver/rsdGL.cpp +++ b/libs/rs/driver/rsdGL.cpp @@ -99,9 +99,8 @@ static void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) { for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) { EGLint value = -1; - EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value); - EGLint error = eglGetError(); - if (returnVal && error == EGL_SUCCESS) { + EGLBoolean returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value); + if (returnVal) { LOGV(" %s: %d (0x%x)", names[j].name, value, value); } } @@ -169,6 +168,24 @@ bool rsdGLInit(const Context *rsc) { configAttribsPtr[1] = EGL_OPENGL_ES2_BIT; configAttribsPtr += 2; + configAttribsPtr[0] = EGL_RED_SIZE; + configAttribsPtr[1] = 8; + configAttribsPtr += 2; + + configAttribsPtr[0] = EGL_GREEN_SIZE; + configAttribsPtr[1] = 8; + configAttribsPtr += 2; + + configAttribsPtr[0] = EGL_BLUE_SIZE; + configAttribsPtr[1] = 8; + configAttribsPtr += 2; + + if (rsc->mUserSurfaceConfig.alphaMin > 0) { + configAttribsPtr[0] = EGL_ALPHA_SIZE; + configAttribsPtr[1] = rsc->mUserSurfaceConfig.alphaMin; + configAttribsPtr += 2; + } + if (rsc->mUserSurfaceConfig.depthMin > 0) { configAttribsPtr[0] = EGL_DEPTH_SIZE; configAttribsPtr[1] = rsc->mUserSurfaceConfig.depthMin; @@ -191,16 +208,53 @@ bool rsdGLInit(const Context *rsc) { eglInitialize(dc->gl.egl.display, &dc->gl.egl.majorVersion, &dc->gl.egl.minorVersion); checkEglError("eglInitialize"); - PixelFormat pf = PIXEL_FORMAT_RGBA_8888; - if (rsc->mUserSurfaceConfig.alphaMin == 0) { - pf = PIXEL_FORMAT_RGBX_8888; - } + EGLBoolean ret; - status_t err = EGLUtils::selectConfigForPixelFormat(dc->gl.egl.display, configAttribs, - pf, &dc->gl.egl.config); - if (err) { - LOGE("%p, couldn't find an EGLConfig matching the screen format\n", rsc); + EGLint numConfigs = -1, n = 0; + ret = eglChooseConfig(dc->gl.egl.display, configAttribs, 0, 0, &numConfigs); + checkEglError("eglGetConfigs", ret); + + if (numConfigs) { + EGLConfig* const configs = new EGLConfig[numConfigs]; + + ret = eglChooseConfig(dc->gl.egl.display, + configAttribs, configs, numConfigs, &n); + if (!ret || !n) { + checkEglError("eglChooseConfig", ret); + LOGE("%p, couldn't find an EGLConfig matching the screen format\n", rsc); + } + + // The first config is guaranteed to over-satisfy the constraints + dc->gl.egl.config = configs[0]; + + // go through the list and skip configs that over-satisfy our needs + for (int i=0 ; i<n ; i++) { + if (rsc->mUserSurfaceConfig.alphaMin <= 0) { + EGLint alphaSize; + eglGetConfigAttrib(dc->gl.egl.display, + configs[i], EGL_ALPHA_SIZE, &alphaSize); + if (alphaSize > 0) { + continue; + } + } + + if (rsc->mUserSurfaceConfig.depthMin <= 0) { + EGLint depthSize; + eglGetConfigAttrib(dc->gl.egl.display, + configs[i], EGL_DEPTH_SIZE, &depthSize); + if (depthSize > 0) { + continue; + } + } + + // Found one! + dc->gl.egl.config = configs[i]; + break; + } + + delete [] configs; } + //if (props.mLogVisual) { if (0) { printEGLConfiguration(dc->gl.egl.display, dc->gl.egl.config); @@ -227,8 +281,8 @@ bool rsdGLInit(const Context *rsc) { return false; } - EGLBoolean ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surfaceDefault, - dc->gl.egl.surfaceDefault, dc->gl.egl.context); + ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surfaceDefault, + dc->gl.egl.surfaceDefault, dc->gl.egl.context); if (ret == EGL_FALSE) { LOGE("eglMakeCurrent returned EGL_FALSE"); checkEglError("eglMakeCurrent", ret); diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk index f9990bb..427bbba 100644 --- a/libs/ui/Android.mk +++ b/libs/ui/Android.mk @@ -43,7 +43,6 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ $(commonSources) \ EGLUtils.cpp \ - EventRecurrence.cpp \ FramebufferNativeWindow.cpp \ GraphicBuffer.cpp \ GraphicBufferAllocator.cpp \ diff --git a/libs/ui/EGLUtils.cpp b/libs/ui/EGLUtils.cpp index f24a71d..020646b 100644 --- a/libs/ui/EGLUtils.cpp +++ b/libs/ui/EGLUtils.cpp @@ -24,6 +24,8 @@ #include <EGL/egl.h> +#include <system/graphics.h> + #include <private/ui/android_natives_priv.h> // ---------------------------------------------------------------------------- @@ -67,31 +69,49 @@ status_t EGLUtils::selectConfigForPixelFormat( return BAD_VALUE; // Get all the "potential match" configs... - if (eglGetConfigs(dpy, NULL, 0, &numConfigs) == EGL_FALSE) + if (eglChooseConfig(dpy, attrs, 0, 0, &numConfigs) == EGL_FALSE) return BAD_VALUE; - EGLConfig* const configs = (EGLConfig*)malloc(sizeof(EGLConfig)*numConfigs); - if (eglChooseConfig(dpy, attrs, configs, numConfigs, &n) == EGL_FALSE) { - free(configs); - return BAD_VALUE; - } - - int i; - EGLConfig config = NULL; - for (i=0 ; i<n ; i++) { - EGLint nativeVisualId = 0; - eglGetConfigAttrib(dpy, configs[i], EGL_NATIVE_VISUAL_ID, &nativeVisualId); - if (nativeVisualId>0 && format == nativeVisualId) { + if (numConfigs) { + EGLConfig* const configs = new EGLConfig[numConfigs]; + if (eglChooseConfig(dpy, attrs, configs, numConfigs, &n) == EGL_FALSE) { + delete [] configs; + return BAD_VALUE; + } + + bool hasAlpha = false; + switch (format) { + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_BGRA_8888: + case HAL_PIXEL_FORMAT_RGBA_5551: + case HAL_PIXEL_FORMAT_RGBA_4444: + hasAlpha = true; + break; + } + + // The first config is guaranteed to over-satisfy the constraints + EGLConfig config = configs[0]; + + // go through the list and skip configs that over-satisfy our needs + int i; + for (i=0 ; i<n ; i++) { + if (!hasAlpha) { + EGLint alphaSize; + eglGetConfigAttrib(dpy, configs[i], EGL_ALPHA_SIZE, &alphaSize); + if (alphaSize > 0) { + continue; + } + } config = configs[i]; break; } - } - free(configs); - - if (i<n) { - *outConfig = config; - return NO_ERROR; + delete [] configs; + + if (i<n) { + *outConfig = config; + return NO_ERROR; + } } return NAME_NOT_FOUND; diff --git a/libs/ui/EventRecurrence.cpp b/libs/ui/EventRecurrence.cpp deleted file mode 100644 index b436b50..0000000 --- a/libs/ui/EventRecurrence.cpp +++ /dev/null @@ -1,484 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - */ - -#include <pim/EventRecurrence.h> -#include <utils/String8.h> -#include <stdio.h> -#include <limits.h> - -namespace android { - -#define FAIL_HERE() do { \ - printf("Parsing failed at line %d\n", __LINE__); \ - return UNKNOWN_ERROR; \ - } while(0) - -EventRecurrence::EventRecurrence() - :freq((freq_t)0), - until(), - count(0), - interval(0), - bysecond(0), - bysecondCount(0), - byminute(0), - byminuteCount(0), - byhour(0), - byhourCount(0), - byday(0), - bydayNum(0), - bydayCount(0), - bymonthday(0), - bymonthdayCount(0), - byyearday(0), - byyeardayCount(0), - byweekno(0), - byweeknoCount(0), - bymonth(0), - bymonthCount(0), - bysetpos(0), - bysetposCount(0), - wkst(0) -{ -} - -EventRecurrence::~EventRecurrence() -{ - delete[] bysecond; - delete[] byminute; - delete[] byhour; - delete[] byday; - delete[] bydayNum; - delete[] byyearday; - delete[] bymonthday; - delete[] byweekno; - delete[] bymonth; - delete[] bysetpos; -} - -enum LHS { - NONE_LHS = 0, - FREQ, - UNTIL, - COUNT, - INTERVAL, - BYSECOND, - BYMINUTE, - BYHOUR, - BYDAY, - BYMONTHDAY, - BYYEARDAY, - BYWEEKNO, - BYMONTH, - BYSETPOS, - WKST -}; - -struct LHSProc -{ - const char16_t* text; - size_t textSize; - uint32_t value; -}; - -const char16_t FREQ_text[] = { 'F', 'R', 'E', 'Q' }; -const char16_t UNTIL_text[] = { 'U', 'N', 'T', 'I', 'L' }; -const char16_t COUNT_text[] = { 'C', 'O', 'U', 'N', 'T' }; -const char16_t INTERVAL_text[] = { 'I', 'N', 'T', 'E', 'R', 'V', 'A', 'L'}; -const char16_t BYSECOND_text[] = { 'B', 'Y', 'S', 'E', 'C', 'O', 'N', 'D' }; -const char16_t BYMINUTE_text[] = { 'B', 'Y', 'M', 'I', 'N', 'U', 'T', 'E' }; -const char16_t BYHOUR_text[] = { 'B', 'Y', 'H', 'O', 'U', 'R' }; -const char16_t BYDAY_text[] = { 'B', 'Y', 'D', 'A', 'Y' }; -const char16_t BYMONTHDAY_text[] = { 'B','Y','M','O','N','T','H','D','A','Y' }; -const char16_t BYYEARDAY_text[] = { 'B','Y','Y','E','A','R','D','A','Y' }; -const char16_t BYWEEKNO_text[] = { 'B', 'Y', 'W', 'E', 'E', 'K', 'N', 'O' }; -const char16_t BYMONTH_text[] = { 'B', 'Y', 'M', 'O', 'N', 'T', 'H' }; -const char16_t BYSETPOS_text[] = { 'B', 'Y', 'S', 'E', 'T', 'P', 'O', 'S' }; -const char16_t WKST_text[] = { 'W', 'K', 'S', 'T' }; - -#define SIZ(x) (sizeof(x)/sizeof(x[0])) - -const LHSProc LHSPROC[] = { - { FREQ_text, SIZ(FREQ_text), FREQ }, - { UNTIL_text, SIZ(UNTIL_text), UNTIL }, - { COUNT_text, SIZ(COUNT_text), COUNT }, - { INTERVAL_text, SIZ(INTERVAL_text), INTERVAL }, - { BYSECOND_text, SIZ(BYSECOND_text), BYSECOND }, - { BYMINUTE_text, SIZ(BYMINUTE_text), BYMINUTE }, - { BYHOUR_text, SIZ(BYHOUR_text), BYHOUR }, - { BYDAY_text, SIZ(BYDAY_text), BYDAY }, - { BYMONTHDAY_text, SIZ(BYMONTHDAY_text), BYMONTHDAY }, - { BYYEARDAY_text, SIZ(BYYEARDAY_text), BYYEARDAY }, - { BYWEEKNO_text, SIZ(BYWEEKNO_text), BYWEEKNO }, - { BYMONTH_text, SIZ(BYMONTH_text), BYMONTH }, - { BYSETPOS_text, SIZ(BYSETPOS_text), BYSETPOS }, - { WKST_text, SIZ(WKST_text), WKST }, - { NULL, 0, NONE_LHS }, -}; - -const char16_t SECONDLY_text[] = { 'S','E','C','O','N','D','L','Y' }; -const char16_t MINUTELY_text[] = { 'M','I','N','U','T','E','L','Y' }; -const char16_t HOURLY_text[] = { 'H','O','U','R','L','Y' }; -const char16_t DAILY_text[] = { 'D','A','I','L','Y' }; -const char16_t WEEKLY_text[] = { 'W','E','E','K','L','Y' }; -const char16_t MONTHLY_text[] = { 'M','O','N','T','H','L','Y' }; -const char16_t YEARLY_text[] = { 'Y','E','A','R','L','Y' }; - -typedef LHSProc FreqProc; - -const FreqProc FREQPROC[] = { - { SECONDLY_text, SIZ(SECONDLY_text), EventRecurrence::SECONDLY }, - { MINUTELY_text, SIZ(MINUTELY_text), EventRecurrence::MINUTELY }, - { HOURLY_text, SIZ(HOURLY_text), EventRecurrence::HOURLY }, - { DAILY_text, SIZ(DAILY_text), EventRecurrence::DAILY }, - { WEEKLY_text, SIZ(WEEKLY_text), EventRecurrence::WEEKLY }, - { MONTHLY_text, SIZ(MONTHLY_text), EventRecurrence::MONTHLY }, - { YEARLY_text, SIZ(YEARLY_text), EventRecurrence::YEARLY }, - { NULL, 0, NONE_LHS }, -}; - -const char16_t SU_text[] = { 'S','U' }; -const char16_t MO_text[] = { 'M','O' }; -const char16_t TU_text[] = { 'T','U' }; -const char16_t WE_text[] = { 'W','E' }; -const char16_t TH_text[] = { 'T','H' }; -const char16_t FR_text[] = { 'F','R' }; -const char16_t SA_text[] = { 'S','A' }; - -const FreqProc WEEKDAYPROC[] = { - { SU_text, SIZ(SU_text), EventRecurrence::SU }, - { MO_text, SIZ(MO_text), EventRecurrence::MO }, - { TU_text, SIZ(TU_text), EventRecurrence::TU }, - { WE_text, SIZ(WE_text), EventRecurrence::WE }, - { TH_text, SIZ(TH_text), EventRecurrence::TH }, - { FR_text, SIZ(FR_text), EventRecurrence::FR }, - { SA_text, SIZ(SA_text), EventRecurrence::SA }, - { NULL, 0, NONE_LHS }, -}; - -// returns the index into LHSPROC for the match or -1 if not found -inline static int -match_proc(const LHSProc* p, const char16_t* str, size_t len) -{ - int i = 0; - while (p->text != NULL) { - if (p->textSize == len) { - if (0 == memcmp(p->text, str, len*sizeof(char16_t))) { - return i; - } - } - p++; - i++; - } - return -1; -} - -// rangeMin and rangeMax are inclusive -static status_t -parse_int(const char16_t* str, size_t len, int* out, - int rangeMin, int rangeMax, bool zeroOK) -{ - char16_t c; - size_t i=0; - - if (len == 0) { - FAIL_HERE(); - } - bool negative = false; - c = str[0]; - if (c == '-' ) { - negative = true; - i++; - } - else if (c == '+') { - i++; - } - int n = 0; - for (; i<len; i++) { - c = str[i]; - if (c < '0' || c > '9') { - FAIL_HERE(); - } - int prev = n; - n *= 10; - // the spec doesn't address how big these numbers can be, - // so we're not going to worry about not being able to represent - // INT_MIN, and if we're going to wrap, we'll just clamp to - // INT_MAX instead - if (n < prev) { - n = INT_MAX; - } else { - n += c - '0'; - } - } - if (negative) { - n = -n; - } - if (n < rangeMin || n > rangeMax) { - FAIL_HERE(); - } - if (!zeroOK && n == 0) { - FAIL_HERE(); - } - *out = n; - return NO_ERROR; -} - -static status_t -parse_int_list(const char16_t* str, size_t len, int* countOut, int** listOut, - int rangeMin, int rangeMax, bool zeroOK, - status_t (*func)(const char16_t*,size_t,int*,int,int,bool)=parse_int) -{ - status_t err; - - if (len == 0) { - *countOut = 0; - *listOut = NULL; - return NO_ERROR; - } - - // make one pass through looking for commas so we know how big to make our - // out array. - int count = 1; - for (size_t i=0; i<len; i++) { - if (str[i] == ',') { - count++; - } - } - - int* list = new int[count]; - const char16_t* p = str; - int commaIndex = 0; - size_t i; - - for (i=0; i<len; i++) { - if (str[i] == ',') { - err = func(p, (str+i-p), list+commaIndex, rangeMin, - rangeMax, zeroOK); - if (err != NO_ERROR) { - goto bail; - } - commaIndex++; - p = str+i+1; - } - } - - err = func(p, (str+i-p), list+commaIndex, rangeMin, rangeMax, zeroOK); - if (err != NO_ERROR) { - goto bail; - } - commaIndex++; - - *countOut = count; - *listOut = list; - - return NO_ERROR; - -bail: - delete[] list; - FAIL_HERE(); -} - -// the numbers here are small, so we pack them both into one value, and then -// split it out later. it lets us reuse all the comma separated list code. -static status_t -parse_byday(const char16_t* s, size_t len, int* out, - int rangeMin, int rangeMax, bool zeroOK) -{ - status_t err; - int n = 0; - const char16_t* p = s; - size_t plen = len; - - if (len > 0) { - char16_t c = s[0]; - if (c == '-' || c == '+' || (c >= '0' && c <= '9')) { - if (len > 1) { - size_t nlen = 0; - c = s[nlen]; - while (nlen < len - && (c == '-' || c == '+' || (c >= '0' && c <= '9'))) { - c = s[nlen]; - nlen++; - } - if (nlen > 0) { - nlen--; - err = parse_int(s, nlen, &n, rangeMin, rangeMax, zeroOK); - if (err != NO_ERROR) { - FAIL_HERE(); - } - p += nlen; - plen -= nlen; - } - } - } - - int index = match_proc(WEEKDAYPROC, p, plen); - if (index >= 0) { - *out = (0xffff0000 & WEEKDAYPROC[index].value) - | (0x0000ffff & n); - return NO_ERROR; - } - } - return UNKNOWN_ERROR; -} - -static void -postprocess_byday(int count, int* byday, int** bydayNum) -{ - int* bdn = new int[count]; - *bydayNum = bdn; - for (int i=0; i<count; i++) { - uint32_t v = byday[i]; - int16_t num = v & 0x0000ffff; - byday[i] = v & 0xffff0000; - // will sign extend: - bdn[i] = num; - } -} - -#define PARSE_INT_LIST_CHECKED(name, rangeMin, rangeMax, zeroOK) \ - if (name##Count != 0 || NO_ERROR != parse_int_list(s, slen, \ - &name##Count, &name, rangeMin, rangeMax, zeroOK)) { \ - FAIL_HERE(); \ - } -status_t -EventRecurrence::parse(const String16& str) -{ - char16_t const* work = str.string(); - size_t len = str.size(); - - int lhsIndex = NONE_LHS; - int index; - - size_t start = 0; - for (size_t i=0; i<len; i++) { - char16_t c = work[i]; - if (c != ';' && i == len-1) { - c = ';'; - i++; - } - if (c == ';' || c == '=') { - if (i != start) { - const char16_t* s = work+start; - const size_t slen = i-start; - - String8 thestring(String16(s, slen)); - - switch (c) - { - case '=': - if (lhsIndex == NONE_LHS) { - lhsIndex = match_proc(LHSPROC, s, slen); - if (lhsIndex >= 0) { - break; - } - } - FAIL_HERE(); - case ';': - { - switch (LHSPROC[lhsIndex].value) - { - case FREQ: - if (this->freq != 0) { - FAIL_HERE(); - } - index = match_proc(FREQPROC, s, slen); - if (index >= 0) { - this->freq = (freq_t)FREQPROC[index].value; - } - break; - case UNTIL: - // XXX should check that this is a valid time - until.setTo(String16(s, slen)); - break; - case COUNT: - if (count != 0 - || NO_ERROR != parse_int(s, slen, - &count, INT_MIN, INT_MAX, true)) { - FAIL_HERE(); - } - break; - case INTERVAL: - if (interval != 0 - || NO_ERROR != parse_int(s, slen, - &interval, INT_MIN, INT_MAX, false)) { - FAIL_HERE(); - } - break; - case BYSECOND: - PARSE_INT_LIST_CHECKED(bysecond, 0, 59, true) - break; - case BYMINUTE: - PARSE_INT_LIST_CHECKED(byminute, 0, 59, true) - break; - case BYHOUR: - PARSE_INT_LIST_CHECKED(byhour, 0, 23, true) - break; - case BYDAY: - if (bydayCount != 0 || NO_ERROR != - parse_int_list(s, slen, &bydayCount, - &byday, -53, 53, false, - parse_byday)) { - FAIL_HERE(); - } - postprocess_byday(bydayCount, byday, &bydayNum); - break; - case BYMONTHDAY: - PARSE_INT_LIST_CHECKED(bymonthday, -31, 31, - false) - break; - case BYYEARDAY: - PARSE_INT_LIST_CHECKED(byyearday, -366, 366, - false) - break; - case BYWEEKNO: - PARSE_INT_LIST_CHECKED(byweekno, -53, 53, - false) - break; - case BYMONTH: - PARSE_INT_LIST_CHECKED(bymonth, 1, 12, false) - break; - case BYSETPOS: - PARSE_INT_LIST_CHECKED(bysetpos, - INT_MIN, INT_MAX, true) - break; - case WKST: - if (this->wkst != 0) { - FAIL_HERE(); - } - index = match_proc(WEEKDAYPROC, s, slen); - if (index >= 0) { - this->wkst = (int)WEEKDAYPROC[index].value; - } - break; - default: - FAIL_HERE(); - } - lhsIndex = NONE_LHS; - break; - } - } - - start = i+1; - } - } - } - - // enforce that there was a FREQ - if (freq == 0) { - FAIL_HERE(); - } - - // default wkst to MO if it wasn't specified - if (wkst == 0) { - wkst = MO; - } - - return NO_ERROR; -} - - -}; // namespace android - - diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp index ffdfe66..c46d6f4 100644 --- a/libs/ui/InputTransport.cpp +++ b/libs/ui/InputTransport.cpp @@ -443,7 +443,8 @@ status_t InputPublisher::appendMotionSample( if (! mPinned || ! mMotionEventSampleDataTail) { LOGE("channel '%s' publisher ~ Cannot append motion sample because there is no current " - "AMOTION_EVENT_ACTION_MOVE event.", mChannel->getName().string()); + "AMOTION_EVENT_ACTION_MOVE or AMOTION_EVENT_ACTION_HOVER_MOVE event.", + mChannel->getName().string()); return INVALID_OPERATION; } diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk index 093189c..774e8c9 100644 --- a/libs/utils/Android.mk +++ b/libs/utils/Android.mk @@ -27,6 +27,7 @@ commonSources:= \ Debug.cpp \ FileMap.cpp \ Flattenable.cpp \ + LinearTransform.cpp \ ObbFile.cpp \ Pool.cpp \ PropertyMap.cpp \ diff --git a/libs/utils/LinearTransform.cpp b/libs/utils/LinearTransform.cpp new file mode 100644 index 0000000..d752415 --- /dev/null +++ b/libs/utils/LinearTransform.cpp @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2011 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 __STDC_LIMIT_MACROS + +#include <assert.h> +#include <stdint.h> + +#include <utils/LinearTransform.h> + +namespace android { + +template<class T> static inline T ABS(T x) { return (x < 0) ? -x : x; } + +// Static math methods involving linear transformations +static bool scale_u64_to_u64( + uint64_t val, + uint32_t N, + uint32_t D, + uint64_t* res, + bool round_up_not_down) { + uint64_t tmp1, tmp2; + uint32_t r; + + assert(res); + assert(D); + + // Let U32(X) denote a uint32_t containing the upper 32 bits of a 64 bit + // integer X. + // Let L32(X) denote a uint32_t containing the lower 32 bits of a 64 bit + // integer X. + // Let X[A, B] with A <= B denote bits A through B of the integer X. + // Let (A | B) denote the concatination of two 32 bit ints, A and B. + // IOW X = (A | B) => U32(X) == A && L32(X) == B + // + // compute M = val * N (a 96 bit int) + // --------------------------------- + // tmp2 = U32(val) * N (a 64 bit int) + // tmp1 = L32(val) * N (a 64 bit int) + // which means + // M = val * N = (tmp2 << 32) + tmp1 + tmp2 = (val >> 32) * N; + tmp1 = (val & UINT32_MAX) * N; + + // compute M[32, 95] + // tmp2 = tmp2 + U32(tmp1) + // = (U32(val) * N) + U32(L32(val) * N) + // = M[32, 95] + tmp2 += tmp1 >> 32; + + // if M[64, 95] >= D, then M/D has bits > 63 set and we have + // an overflow. + if ((tmp2 >> 32) >= D) { + *res = UINT64_MAX; + return false; + } + + // Divide. Going in we know + // tmp2 = M[32, 95] + // U32(tmp2) < D + r = tmp2 % D; + tmp2 /= D; + + // At this point + // tmp1 = L32(val) * N + // tmp2 = M[32, 95] / D + // = (M / D)[32, 95] + // r = M[32, 95] % D + // U32(tmp2) = 0 + // + // compute tmp1 = (r | M[0, 31]) + tmp1 = (tmp1 & UINT32_MAX) | ((uint64_t)r << 32); + + // Divide again. Keep the remainder around in order to round properly. + r = tmp1 % D; + tmp1 /= D; + + // At this point + // tmp2 = (M / D)[32, 95] + // tmp1 = (M / D)[ 0, 31] + // r = M % D + // U32(tmp1) = 0 + // U32(tmp2) = 0 + + // Pack the result and deal with the round-up case (As well as the + // remote possiblility over overflow in such a case). + *res = (tmp2 << 32) | tmp1; + if (r && round_up_not_down) { + ++(*res); + if (!(*res)) { + *res = UINT64_MAX; + return false; + } + } + + return true; +} + +static bool linear_transform_s64_to_s64( + int64_t val, + int64_t basis1, + int32_t N, + uint32_t D, + int64_t basis2, + int64_t* out) { + uint64_t scaled, res; + uint64_t abs_val; + bool is_neg; + + if (!out) + return false; + + // Compute abs(val - basis_64). Keep track of whether or not this delta + // will be negative after the scale opertaion. + if (val < basis1) { + is_neg = true; + abs_val = basis1 - val; + } else { + is_neg = false; + abs_val = val - basis1; + } + + if (N < 0) + is_neg = !is_neg; + + if (!scale_u64_to_u64(abs_val, + ABS(N), + D, + &scaled, + is_neg)) + return false; // overflow/undeflow + + // if scaled is >= 0x8000<etc>, then we are going to overflow or + // underflow unless ABS(basis2) is large enough to pull us back into the + // non-overflow/underflow region. + if (scaled & INT64_MIN) { + if (is_neg && (basis2 < 0)) + return false; // certain underflow + + if (!is_neg && (basis2 >= 0)) + return false; // certain overflow + + if (ABS(basis2) <= static_cast<int64_t>(scaled & INT64_MAX)) + return false; // not enough + + // Looks like we are OK + *out = (is_neg ? (-scaled) : scaled) + basis2; + } else { + // Scaled fits within signed bounds, so we just need to check for + // over/underflow for two signed integers. Basically, if both scaled + // and basis2 have the same sign bit, and the result has a different + // sign bit, then we have under/overflow. An easy way to compute this + // is + // (scaled_signbit XNOR basis_signbit) && + // (scaled_signbit XOR res_signbit) + // == + // (scaled_signbit XOR basis_signbit XOR 1) && + // (scaled_signbit XOR res_signbit) + + if (is_neg) + scaled = -scaled; + res = scaled + basis2; + + if ((scaled ^ basis2 ^ INT64_MIN) & (scaled ^ res) & INT64_MIN) + return false; + + *out = res; + } + + return true; +} + +bool LinearTransform::doForwardTransform(int64_t a_in, int64_t* b_out) const { + if (0 == a_to_b_denom) + return false; + + return linear_transform_s64_to_s64(a_in, + a_zero, + a_to_b_numer, + a_to_b_denom, + b_zero, + b_out); +} + +bool LinearTransform::doReverseTransform(int64_t b_in, int64_t* a_out) const { + if (0 == a_to_b_numer) + return false; + + return linear_transform_s64_to_s64(b_in, + b_zero, + a_to_b_denom, + a_to_b_numer, + a_zero, + a_out); +} + +template <class T> void LinearTransform::reduce(T* N, T* D) { + T a, b; + if (!N || !D || !(*D)) { + assert(false); + return; + } + + a = *N; + b = *D; + + if (a == 0) { + *D = 1; + return; + } + + // This implements Euclid's method to find GCD. + if (a < b) { + T tmp = a; + a = b; + b = tmp; + } + + while (1) { + // a is now the greater of the two. + const T remainder = a % b; + if (remainder == 0) { + *N /= b; + *D /= b; + return; + } + // by swapping remainder and b, we are guaranteeing that a is + // still the greater of the two upon entrance to the loop. + a = b; + b = remainder; + } +}; + +template void LinearTransform::reduce<uint64_t>(uint64_t* N, uint64_t* D); +template void LinearTransform::reduce<uint32_t>(uint32_t* N, uint32_t* D); + +void LinearTransform::reduce(int32_t* N, uint32_t* D) { + if (N && D && *D) { + if (*N < 0) { + *N = -(*N); + reduce(reinterpret_cast<uint32_t*>(N), D); + *N = -(*N); + } else { + reduce(reinterpret_cast<uint32_t*>(N), D); + } + } +} + +} // namespace android diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp index 15bb1d2..50312e7 100644 --- a/libs/utils/Threads.cpp +++ b/libs/utils/Threads.cpp @@ -316,6 +316,10 @@ int androidSetThreadSchedulingGroup(pid_t tid, int grp) #if defined(HAVE_PTHREADS) pthread_once(&gDoSchedulingGroupOnce, checkDoSchedulingGroup); if (gDoSchedulingGroup) { + // set_sched_policy does not support tid == 0 + if (tid == 0) { + tid = androidGetTid(); + } if (set_sched_policy(tid, (grp == ANDROID_TGROUP_BG_NONINTERACT) ? SP_BACKGROUND : SP_FOREGROUND)) { return PERMISSION_DENIED; @@ -842,6 +846,25 @@ status_t Thread::requestExitAndWait() return mStatus; } +status_t Thread::join() +{ + Mutex::Autolock _l(mLock); + if (mThread == getThreadId()) { + LOGW( + "Thread (this=%p): don't call join() from this " + "Thread object's thread. It's a guaranteed deadlock!", + this); + + return WOULD_BLOCK; + } + + while (mRunning == true) { + mThreadExitedCondition.wait(mLock); + } + + return mStatus; +} + bool Thread::exitPending() const { Mutex::Autolock _l(mLock); |