summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/binder/Android.mk2
-rw-r--r--libs/binder/IMemory.cpp53
-rw-r--r--libs/binder/MemoryHeapBase.cpp15
-rw-r--r--libs/binder/Permission.cpp88
-rw-r--r--libs/binder/PermissionCache.cpp113
-rw-r--r--libs/camera/Android.mk4
-rw-r--r--libs/camera/Camera.cpp56
-rw-r--r--libs/camera/ICameraRecordingProxy.cpp109
-rw-r--r--libs/camera/ICameraRecordingProxyListener.cpp75
-rw-r--r--libs/gui/ISurfaceComposer.cpp35
-rw-r--r--libs/gui/ISurfaceComposerClient.cpp25
-rw-r--r--libs/gui/LayerState.cpp11
-rw-r--r--libs/gui/Surface.cpp4
-rw-r--r--libs/gui/SurfaceComposerClient.cpp593
-rw-r--r--libs/gui/SurfaceTexture.cpp64
-rw-r--r--libs/gui/SurfaceTextureClient.cpp45
-rw-r--r--libs/gui/tests/SurfaceTexture_test.cpp224
-rw-r--r--libs/gui/tests/Surface_test.cpp4
-rw-r--r--libs/hwui/Caches.cpp2
-rw-r--r--libs/hwui/DisplayListRenderer.cpp48
-rw-r--r--libs/hwui/DisplayListRenderer.h18
-rw-r--r--libs/hwui/LayerRenderer.cpp74
-rw-r--r--libs/hwui/LayerRenderer.h4
-rw-r--r--libs/hwui/OpenGLRenderer.cpp2
-rw-r--r--libs/hwui/ResourceCache.cpp27
-rw-r--r--libs/hwui/SkiaColorFilter.h2
-rw-r--r--libs/rs/driver/rsdAllocation.cpp4
-rw-r--r--libs/rs/driver/rsdGL.cpp5
-rw-r--r--libs/rs/driver/rsdRuntimeMath.cpp103
-rw-r--r--libs/rs/driver/rsdRuntimeStubs.cpp4
-rw-r--r--libs/rs/rs.spec1
-rw-r--r--libs/rs/scriptc/rs_math.rsh222
-rw-r--r--libs/ui/Android.mk1
-rw-r--r--libs/ui/EventRecurrence.cpp484
-rw-r--r--libs/ui/InputTransport.cpp3
-rw-r--r--libs/utils/Android.mk1
-rw-r--r--libs/utils/BackupData.cpp3
-rw-r--r--libs/utils/LinearTransform.cpp262
38 files changed, 1689 insertions, 1101 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/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/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/Surface.cpp b/libs/gui/Surface.cpp
index 4d1d923..9185e1e 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -421,6 +421,10 @@ status_t Surface::validate(bool inCancelBuffer) const
return NO_ERROR;
}
+sp<ISurfaceTexture> Surface::getSurfaceTexture() {
+ return mSurface != NULL ? mSurface->getSurfaceTexture() : NULL;
+}
+
sp<IBinder> Surface::asBinder() const {
return mSurface!=0 ? mSurface->asBinder() : 0;
}
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 3cecdb4..3bf6477 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -78,7 +78,7 @@ static float mtxRot270[16] = {
static void mtxMul(float out[16], const float a[16], const float b[16]);
-SurfaceTexture::SurfaceTexture(GLuint tex) :
+SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode) :
mDefaultWidth(1),
mDefaultHeight(1),
mPixelFormat(PIXEL_FORMAT_RGBA_8888),
@@ -91,7 +91,8 @@ SurfaceTexture::SurfaceTexture(GLuint tex) :
mCurrentTimestamp(0),
mNextTransform(0),
mTexName(tex),
- mSynchronousMode(false) {
+ mSynchronousMode(false),
+ mAllowSynchronousMode(allowSynchronousMode) {
LOGV("SurfaceTexture::SurfaceTexture");
sp<ISurfaceComposer> composer(ComposerService::getComposerService());
mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
@@ -147,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) {
@@ -207,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;
}
@@ -371,6 +377,9 @@ status_t SurfaceTexture::setSynchronousMode(bool enabled) {
Mutex::Autolock lock(mMutex);
status_t err = OK;
+ if (!mAllowSynchronousMode && enabled)
+ return err;
+
if (!enabled) {
// going to asynchronous mode, drain the queue
while (mSynchronousMode != enabled && !mQueue.isEmpty()) {
@@ -413,17 +422,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
@@ -479,24 +493,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) {
@@ -534,7 +538,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)
@@ -549,17 +553,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)
@@ -700,10 +704,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/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index 22b0852..b9b2310 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -143,12 +143,40 @@ int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer) {
int SurfaceTextureClient::cancelBuffer(android_native_buffer_t* buffer) {
LOGV("SurfaceTextureClient::cancelBuffer");
Mutex::Autolock lock(mMutex);
+ int i = getSlotFromBufferLocked(buffer);
+ if (i < 0) {
+ return i;
+ }
+ mSurfaceTexture->cancelBuffer(i);
+ return OK;
+}
+
+int SurfaceTextureClient::getSlotFromBufferLocked(
+ android_native_buffer_t* buffer) const {
+ bool dumpedState = false;
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
- if (mSlots[i]->handle == buffer->handle) {
- mSurfaceTexture->cancelBuffer(i);
- return OK;
+ // XXX: Dump the slots whenever we hit a NULL entry while searching for
+ // a buffer.
+ if (mSlots[i] == NULL) {
+ if (!dumpedState) {
+ LOGD("getSlotFromBufferLocked: encountered NULL buffer in slot %d "
+ "looking for buffer %p", i, buffer->handle);
+ for (int j = 0; j < NUM_BUFFER_SLOTS; j++) {
+ if (mSlots[j] == NULL) {
+ LOGD("getSlotFromBufferLocked: %02d: NULL", j);
+ } else {
+ LOGD("getSlotFromBufferLocked: %02d: %p", j, mSlots[j]->handle);
+ }
+ }
+ dumpedState = true;
+ }
+ }
+
+ if (mSlots[i] != NULL && mSlots[i]->handle == buffer->handle) {
+ return i;
}
}
+ LOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle);
return BAD_VALUE;
}
@@ -169,13 +197,12 @@ int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer) {
} else {
timestamp = mTimestamp;
}
- for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
- if (mSlots[i]->handle == buffer->handle) {
- return mSurfaceTexture->queueBuffer(i, timestamp);
- }
+ int i = getSlotFromBufferLocked(buffer);
+ if (i < 0) {
+ return i;
}
- LOGE("queueBuffer: unknown buffer queued");
- return BAD_VALUE;
+ mSurfaceTexture->queueBuffer(i, timestamp);
+ return OK;
}
int SurfaceTextureClient::query(int what, int* value) const {
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index f6cefa6..c06400e 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,
@@ -173,11 +173,11 @@ protected:
}
virtual EGLint getSurfaceWidth() {
- return 64;
+ return 512;
}
virtual EGLint getSurfaceHeight() {
- return 64;
+ return 512;
}
void loadShader(GLenum shaderType, const char* pSource, GLuint* outShader) {
@@ -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;
@@ -526,18 +551,19 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferNpot) {
glClearColor(0.2, 0.2, 0.2, 0.2);
glClear(GL_COLOR_BUFFER_BIT);
+ glViewport(0, 0, texWidth, texHeight);
drawTexture();
EXPECT_TRUE(checkPixel( 0, 0, 255, 127, 255, 255));
EXPECT_TRUE(checkPixel(63, 0, 0, 133, 0, 255));
- EXPECT_TRUE(checkPixel(63, 63, 0, 133, 0, 255));
- EXPECT_TRUE(checkPixel( 0, 63, 255, 127, 255, 255));
+ EXPECT_TRUE(checkPixel(63, 65, 0, 133, 0, 255));
+ EXPECT_TRUE(checkPixel( 0, 65, 255, 127, 255, 255));
- EXPECT_TRUE(checkPixel(22, 44, 247, 70, 255, 255));
- EXPECT_TRUE(checkPixel(45, 52, 209, 32, 235, 255));
- EXPECT_TRUE(checkPixel(52, 51, 100, 255, 73, 255));
+ EXPECT_TRUE(checkPixel(22, 44, 255, 127, 255, 255));
+ EXPECT_TRUE(checkPixel(45, 52, 255, 127, 255, 255));
+ EXPECT_TRUE(checkPixel(52, 51, 98, 255, 73, 255));
EXPECT_TRUE(checkPixel( 7, 31, 155, 0, 118, 255));
- EXPECT_TRUE(checkPixel(31, 9, 148, 71, 110, 255));
+ EXPECT_TRUE(checkPixel(31, 9, 107, 24, 87, 255));
EXPECT_TRUE(checkPixel(29, 35, 255, 127, 255, 255));
EXPECT_TRUE(checkPixel(36, 22, 155, 29, 0, 255));
}
@@ -570,6 +596,7 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferPow2) {
glClearColor(0.2, 0.2, 0.2, 0.2);
glClear(GL_COLOR_BUFFER_BIT);
+ glViewport(0, 0, texWidth, texHeight);
drawTexture();
EXPECT_TRUE(checkPixel( 0, 0, 0, 133, 0, 255));
@@ -628,6 +655,7 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferWithCrop) {
glClearColor(0.2, 0.2, 0.2, 0.2);
glClear(GL_COLOR_BUFFER_BIT);
+ glViewport(0, 0, 64, 64);
drawTexture();
EXPECT_TRUE(checkPixel( 0, 0, 82, 255, 35, 255));
@@ -645,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) {
@@ -675,28 +854,29 @@ TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromCpuFilledRGBABufferNpot) {
glClearColor(0.2, 0.2, 0.2, 0.2);
glClear(GL_COLOR_BUFFER_BIT);
+ glViewport(0, 0, texWidth, texHeight);
drawTexture();
EXPECT_TRUE(checkPixel( 0, 0, 35, 35, 35, 35));
EXPECT_TRUE(checkPixel(63, 0, 231, 231, 231, 231));
- EXPECT_TRUE(checkPixel(63, 63, 231, 231, 231, 231));
- EXPECT_TRUE(checkPixel( 0, 63, 35, 35, 35, 35));
+ EXPECT_TRUE(checkPixel(63, 65, 231, 231, 231, 231));
+ EXPECT_TRUE(checkPixel( 0, 65, 35, 35, 35, 35));
EXPECT_TRUE(checkPixel(15, 10, 35, 231, 231, 231));
- EXPECT_TRUE(checkPixel(24, 63, 35, 231, 231, 35));
- EXPECT_TRUE(checkPixel(19, 40, 87, 179, 35, 35));
+ EXPECT_TRUE(checkPixel(24, 63, 38, 228, 231, 35));
+ EXPECT_TRUE(checkPixel(19, 40, 35, 231, 35, 35));
EXPECT_TRUE(checkPixel(38, 30, 231, 35, 35, 35));
EXPECT_TRUE(checkPixel(42, 54, 35, 35, 35, 231));
- EXPECT_TRUE(checkPixel(37, 33, 35, 231, 231, 231));
+ EXPECT_TRUE(checkPixel(37, 33, 228, 38, 38, 38));
EXPECT_TRUE(checkPixel(31, 8, 231, 35, 35, 231));
- EXPECT_TRUE(checkPixel(36, 47, 231, 35, 231, 231));
- EXPECT_TRUE(checkPixel(24, 63, 35, 231, 231, 35));
- EXPECT_TRUE(checkPixel(48, 3, 231, 231, 35, 35));
+ EXPECT_TRUE(checkPixel(36, 47, 228, 35, 231, 231));
+ EXPECT_TRUE(checkPixel(24, 63, 38, 228, 231, 35));
+ EXPECT_TRUE(checkPixel(48, 3, 228, 228, 38, 35));
EXPECT_TRUE(checkPixel(54, 50, 35, 231, 231, 231));
- EXPECT_TRUE(checkPixel(24, 25, 191, 191, 231, 231));
- EXPECT_TRUE(checkPixel(10, 9, 93, 93, 231, 231));
+ EXPECT_TRUE(checkPixel(24, 25, 41, 41, 231, 231));
+ EXPECT_TRUE(checkPixel(10, 9, 38, 38, 231, 231));
EXPECT_TRUE(checkPixel(29, 4, 35, 35, 35, 231));
- EXPECT_TRUE(checkPixel(56, 31, 35, 231, 231, 35));
+ EXPECT_TRUE(checkPixel(56, 31, 38, 228, 231, 35));
EXPECT_TRUE(checkPixel(58, 55, 35, 35, 231, 231));
}
@@ -730,6 +910,7 @@ TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromCpuFilledRGBABufferPow2) {
glClearColor(0.2, 0.2, 0.2, 0.2);
glClear(GL_COLOR_BUFFER_BIT);
+ glViewport(0, 0, texWidth, texHeight);
drawTexture();
EXPECT_TRUE(checkPixel( 0, 0, 231, 231, 231, 231));
@@ -803,6 +984,7 @@ TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromGLFilledRGBABufferPow2) {
glClearColor(0.2, 0.2, 0.2, 0.2);
glClear(GL_COLOR_BUFFER_BIT);
+ glViewport(0, 0, texWidth, texHeight);
drawTexture();
EXPECT_TRUE(checkPixel( 0, 0, 153, 153, 153, 153));
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 35c8640..450cdf1 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -36,10 +36,10 @@ protected:
ASSERT_TRUE(mSurfaceControl != NULL);
ASSERT_TRUE(mSurfaceControl->isValid());
- ASSERT_EQ(NO_ERROR, mComposerClient->openTransaction());
+ SurfaceComposerClient::openGlobalTransaction();
ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(30000));
ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
- ASSERT_EQ(NO_ERROR, mComposerClient->closeTransaction());
+ SurfaceComposerClient::closeGlobalTransaction();
mSurface = mSurfaceControl->getSurface();
ASSERT_TRUE(mSurface != NULL);
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index b0d8cf9..563d7e4 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -57,7 +57,7 @@ Caches::Caches(): Singleton<Caches>(), blend(false), lastSrcMode(GL_ZERO),
LOGD("Enabling debug mode %d", mDebugLevel);
#if RENDER_LAYERS_AS_REGIONS
- LOGD("Layers will be composited as regions");
+ INIT_LOGD("Layers will be composited as regions");
#endif
}
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index afab26a..8b1caeee 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -101,8 +101,14 @@ void DisplayList::clearResources() {
}
mBitmapResources.clear();
+ for (size_t i = 0; i < mFilterResources.size(); i++) {
+ caches.resourceCache.decrementRefcount(mFilterResources.itemAt(i));
+ }
+ mFilterResources.clear();
+
for (size_t i = 0; i < mShaders.size(); i++) {
caches.resourceCache.decrementRefcount(mShaders.itemAt(i));
+ caches.resourceCache.destructor(mShaders.itemAt(i));
}
mShaders.clear();
@@ -151,11 +157,18 @@ void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorde
caches.resourceCache.incrementRefcount(resource);
}
+ const Vector<SkiaColorFilter*> &filterResources = recorder.getFilterResources();
+ for (size_t i = 0; i < filterResources.size(); i++) {
+ SkiaColorFilter* resource = filterResources.itemAt(i);
+ mFilterResources.add(resource);
+ caches.resourceCache.incrementRefcount(resource);
+ }
+
const Vector<SkiaShader*> &shaders = recorder.getShaders();
for (size_t i = 0; i < shaders.size(); i++) {
- SkiaShader* shader = shaders.itemAt(i);
- mShaders.add(shader);
- caches.resourceCache.incrementRefcount(shader);
+ SkiaShader* resource = shaders.itemAt(i);
+ mShaders.add(resource);
+ caches.resourceCache.incrementRefcount(resource);
}
const Vector<SkPaint*> &paints = recorder.getPaints();
@@ -686,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: {
@@ -705,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: {
@@ -786,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: {
@@ -873,21 +895,27 @@ void DisplayListRenderer::reset() {
Caches& caches = Caches::getInstance();
for (size_t i = 0; i < mBitmapResources.size(); i++) {
- SkBitmap* resource = mBitmapResources.itemAt(i);
- caches.resourceCache.decrementRefcount(resource);
+ caches.resourceCache.decrementRefcount(mBitmapResources.itemAt(i));
}
mBitmapResources.clear();
+ for (size_t i = 0; i < mFilterResources.size(); i++) {
+ caches.resourceCache.decrementRefcount(mFilterResources.itemAt(i));
+ }
+ mFilterResources.clear();
+
for (size_t i = 0; i < mShaders.size(); i++) {
- caches.resourceCache.decrementRefcount(mShaders.itemAt(i));
+ caches.resourceCache.decrementRefcount(mShaders.itemAt(i));
}
mShaders.clear();
mShaderMap.clear();
mPaints.clear();
mPaintMap.clear();
+
mPaths.clear();
mPathMap.clear();
+
mMatrices.clear();
}
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index dcf2cf2..b83259f 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -292,6 +292,10 @@ public:
return mBitmapResources;
}
+ const Vector<SkiaColorFilter*>& getFilterResources() const {
+ return mFilterResources;
+ }
+
const Vector<SkiaShader*>& getShaders() const {
return mShaders;
}
@@ -308,10 +312,6 @@ public:
return mMatrices;
}
- const Vector<SkiaColorFilter*>& getFilterResources() const {
- return mFilterResources;
- }
-
private:
void insertRestoreToCount() {
if (mRestoreSaveCount >= 0) {
@@ -419,7 +419,9 @@ private:
inline void addMatrix(SkMatrix* matrix) {
// Copying the matrix is cheap and prevents against the user changing the original
// matrix before the operation that uses it
- addInt((int) new SkMatrix(*matrix));
+ SkMatrix* copy = new SkMatrix(*matrix);
+ addInt((int) copy);
+ mMatrices.add(copy);
}
inline void addBitmap(SkBitmap* bitmap) {
@@ -429,8 +431,7 @@ private:
// which doesn't seem worth the extra cycles for this unlikely case.
addInt((int) bitmap);
mBitmapResources.add(bitmap);
- Caches& caches = Caches::getInstance();
- caches.resourceCache.incrementRefcount(bitmap);
+ Caches::getInstance().resourceCache.incrementRefcount(bitmap);
}
inline void addShader(SkiaShader* shader) {
@@ -454,8 +455,7 @@ private:
inline void addColorFilter(SkiaColorFilter* colorFilter) {
addInt((int) colorFilter);
mFilterResources.add(colorFilter);
- Caches& caches = Caches::getInstance();
- caches.resourceCache.incrementRefcount(colorFilter);
+ Caches::getInstance().resourceCache.incrementRefcount(colorFilter);
}
Vector<SkBitmap*> mBitmapResources;
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 77e63d7..e034a86 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -166,30 +166,6 @@ void LayerRenderer::generateMesh() {
// Layers management
///////////////////////////////////////////////////////////////////////////////
-Layer* LayerRenderer::createTextureLayer() {
- LAYER_RENDERER_LOGD("Creating new texture layer");
-
- Layer* layer = new Layer(0, 0);
- layer->isCacheable = false;
- layer->isTextureLayer = true;
- layer->blend = true;
- 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);
@@ -269,24 +245,56 @@ bool LayerRenderer::resizeLayer(Layer* layer, uint32_t width, uint32_t height) {
return true;
}
+static void setTextureParameters(Layer* layer) {
+ glBindTexture(layer->renderTarget, layer->texture);
+
+ 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);
+}
+
+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();
+ layer->renderTarget = GL_NONE; // see ::updateTextureLayer()
+
+ glActiveTexture(GL_TEXTURE0);
+ glGenTextures(1, &layer->texture);
+
+ return layer;
+}
+
void LayerRenderer::updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
- GLenum renderTarget, float* transform) {
+ bool isOpaque, GLenum renderTarget, float* transform) {
if (layer) {
+ layer->blend = !isOpaque;
layer->width = width;
layer->height = 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);
-
- 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->renderTarget) {
+ layer->renderTarget = renderTarget;
+ setTextureParameters(layer);
+ }
}
}
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index 797dfc6..2246573 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -55,11 +55,11 @@ public:
Region* getRegion();
GLint getTargetFbo();
- static Layer* createTextureLayer();
+ static Layer* createTextureLayer(bool isOpaque);
static Layer* createLayer(uint32_t width, uint32_t height, bool isOpaque = false);
static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height);
static void updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
- GLenum renderTarget, float* transform);
+ bool isOpaque, GLenum renderTarget, float* transform);
static void destroyLayer(Layer* layer);
static void destroyLayerDeferred(Layer* layer);
static bool copyLayer(Layer* layer, SkBitmap* bitmap);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 88774c6..1c06a0b 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -639,7 +639,7 @@ void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
setupDrawTextureTransform();
setupDrawColor(alpha, alpha, alpha, alpha);
setupDrawColorFilter();
- setupDrawBlending(layer->blend, layer->mode);
+ setupDrawBlending(layer->blend || layer->alpha < 255, layer->mode);
setupDrawProgram();
setupDrawModelView(rect.left, rect.top, rect.right, rect.bottom);
setupDrawPureColorUniforms();
diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp
index 9aade51..cd2c405 100644
--- a/libs/hwui/ResourceCache.cpp
+++ b/libs/hwui/ResourceCache.cpp
@@ -48,9 +48,6 @@ ResourceCache::~ResourceCache() {
void ResourceCache::incrementRefcount(void* resource, ResourceType resourceType) {
Mutex::Autolock _l(mLock);
- for (size_t i = 0; i < mCache->size(); ++i) {
- void* ref = mCache->valueAt(i);
- }
ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL;
if (ref == NULL || mCache->size() == 0) {
ref = new ResourceReference(resourceType);
@@ -144,7 +141,6 @@ void ResourceCache::destructor(SkPath* resource) {
ref->destroyed = true;
if (ref->refCount == 0) {
deleteResourceReference(resource, ref);
- return;
}
}
@@ -162,7 +158,6 @@ void ResourceCache::destructor(SkBitmap* resource) {
ref->destroyed = true;
if (ref->refCount == 0) {
deleteResourceReference(resource, ref);
- return;
}
}
@@ -180,7 +175,6 @@ void ResourceCache::destructor(SkiaShader* resource) {
ref->destroyed = true;
if (ref->refCount == 0) {
deleteResourceReference(resource, ref);
- return;
}
}
@@ -195,7 +189,6 @@ void ResourceCache::destructor(SkiaColorFilter* resource) {
ref->destroyed = true;
if (ref->refCount == 0) {
deleteResourceReference(resource, ref);
- return;
}
}
@@ -209,36 +202,32 @@ void ResourceCache::deleteResourceReference(void* resource, ResourceReference* r
}
if (ref->destroyed) {
switch (ref->resourceType) {
- case kBitmap:
- {
- SkBitmap* bitmap = (SkBitmap*)resource;
+ case kBitmap: {
+ SkBitmap* bitmap = (SkBitmap*) resource;
if (Caches::hasInstance()) {
Caches::getInstance().textureCache.removeDeferred(bitmap);
}
delete bitmap;
}
break;
- case kPath:
- {
- SkPath* path = (SkPath*)resource;
+ case kPath: {
+ SkPath* path = (SkPath*) resource;
if (Caches::hasInstance()) {
Caches::getInstance().pathCache.removeDeferred(path);
}
delete path;
}
break;
- case kShader:
- {
- SkiaShader* shader = (SkiaShader*)resource;
+ case kShader: {
+ SkiaShader* shader = (SkiaShader*) resource;
if (Caches::hasInstance()) {
Caches::getInstance().gradientCache.removeDeferred(shader->getSkShader());
}
delete shader;
}
break;
- case kColorFilter:
- {
- SkiaColorFilter* filter = (SkiaColorFilter*)resource;
+ case kColorFilter: {
+ SkiaColorFilter* filter = (SkiaColorFilter*) resource;
delete filter;
}
break;
diff --git a/libs/hwui/SkiaColorFilter.h b/libs/hwui/SkiaColorFilter.h
index bf45e13..1bf475c 100644
--- a/libs/hwui/SkiaColorFilter.h
+++ b/libs/hwui/SkiaColorFilter.h
@@ -59,7 +59,7 @@ struct SkiaColorFilter {
return mType;
}
- SkColorFilter *getSkColorFilter() {
+ SkColorFilter* getSkColorFilter() {
return mSkFilter;
}
diff --git a/libs/rs/driver/rsdAllocation.cpp b/libs/rs/driver/rsdAllocation.cpp
index 01a0cf6..17dd931 100644
--- a/libs/rs/driver/rsdAllocation.cpp
+++ b/libs/rs/driver/rsdAllocation.cpp
@@ -460,8 +460,8 @@ void rsdAllocationData2D_alloc_script(const android::renderscript::Context *rsc,
uint8_t *srcPtr = getOffsetPtr(srcAlloc, srcXoff, srcYoff + i, srcLod, srcFace);
memcpy(dstPtr, srcPtr, w * elementSize);
- LOGE("COPIED dstXoff(%u), dstYoff(%u), dstLod(%u), dstFace(%u), w(%u), h(%u), srcXoff(%u), srcYoff(%u), srcLod(%u), srcFace(%u)",
- dstXoff, dstYoff, dstLod, dstFace, w, h, srcXoff, srcYoff, srcLod, srcFace);
+ //LOGE("COPIED dstXoff(%u), dstYoff(%u), dstLod(%u), dstFace(%u), w(%u), h(%u), srcXoff(%u), srcYoff(%u), srcLod(%u), srcFace(%u)",
+ // dstXoff, dstYoff, dstLod, dstFace, w, h, srcXoff, srcYoff, srcLod, srcFace);
}
}
diff --git a/libs/rs/driver/rsdGL.cpp b/libs/rs/driver/rsdGL.cpp
index 3ff03b4..1f7bb0f 100644
--- a/libs/rs/driver/rsdGL.cpp
+++ b/libs/rs/driver/rsdGL.cpp
@@ -321,8 +321,13 @@ bool rsdGLSetSurface(const Context *rsc, uint32_t w, uint32_t h, RsNativeWindow
dc->gl.height = 1;
}
+ if (dc->gl.wndSurface != NULL) {
+ dc->gl.wndSurface->decStrong(NULL);
+ }
+
dc->gl.wndSurface = (ANativeWindow *)sur;
if (dc->gl.wndSurface != NULL) {
+ dc->gl.wndSurface->incStrong(NULL);
dc->gl.width = w;
dc->gl.height = h;
diff --git a/libs/rs/driver/rsdRuntimeMath.cpp b/libs/rs/driver/rsdRuntimeMath.cpp
index acb990d..d29da7e 100644
--- a/libs/rs/driver/rsdRuntimeMath.cpp
+++ b/libs/rs/driver/rsdRuntimeMath.cpp
@@ -268,6 +268,87 @@ static float SC_frac(float v) {
}
+static int32_t SC_AtomicCas(volatile int32_t *ptr, int32_t expectedValue, int32_t newValue) {
+ int32_t prev;
+
+ do {
+ int32_t ret = android_atomic_release_cas(expectedValue, newValue, ptr);
+ if (!ret) {
+ // The android cas return 0 if it wrote the value. This means the
+ // previous value was the expected value and we can return.
+ return expectedValue;
+ }
+ // We didn't write the value and need to load the "previous" value.
+ prev = *ptr;
+
+ // A race condition exists where the expected value could appear after our cas failed
+ // above. In this case loop until we have a legit previous value or the
+ // write passes.
+ } while (prev == expectedValue);
+ return prev;
+}
+
+
+static int32_t SC_AtomicInc(volatile int32_t *ptr) {
+ return android_atomic_inc(ptr);
+}
+
+static int32_t SC_AtomicDec(volatile int32_t *ptr) {
+ return android_atomic_dec(ptr);
+}
+
+static int32_t SC_AtomicAdd(volatile int32_t *ptr, int32_t value) {
+ return android_atomic_add(value, ptr);
+}
+
+static int32_t SC_AtomicSub(volatile int32_t *ptr, int32_t value) {
+ int32_t prev, status;
+ do {
+ prev = *ptr;
+ status = android_atomic_release_cas(prev, prev - value, ptr);
+ } while (__builtin_expect(status != 0, 0));
+ return prev;
+}
+
+static int32_t SC_AtomicAnd(volatile int32_t *ptr, int32_t value) {
+ return android_atomic_and(value, ptr);
+}
+
+static int32_t SC_AtomicOr(volatile int32_t *ptr, int32_t value) {
+ return android_atomic_or(value, ptr);
+}
+
+static int32_t SC_AtomicXor(volatile int32_t *ptr, int32_t value) {
+ int32_t prev, status;
+ do {
+ prev = *ptr;
+ status = android_atomic_release_cas(prev, prev ^ value, ptr);
+ } while (__builtin_expect(status != 0, 0));
+ return prev;
+}
+
+static int32_t SC_AtomicMin(volatile int32_t *ptr, int32_t value) {
+ int32_t prev, status;
+ do {
+ prev = *ptr;
+ int32_t n = rsMin(value, prev);
+ status = android_atomic_release_cas(prev, n, ptr);
+ } while (__builtin_expect(status != 0, 0));
+ return prev;
+}
+
+static int32_t SC_AtomicMax(volatile int32_t *ptr, int32_t value) {
+ int32_t prev, status;
+ do {
+ prev = *ptr;
+ int32_t n = rsMax(value, prev);
+ status = android_atomic_release_cas(prev, n, ptr);
+ } while (__builtin_expect(status != 0, 0));
+ return prev;
+}
+
+
+
//////////////////////////////////////////////////////////////////////////////
// Class implementation
//////////////////////////////////////////////////////////////////////////////
@@ -425,6 +506,28 @@ static RsdSymbolTable gSyms[] = {
{ "_Z6rsRandff", (void *)&SC_randf2, true },
{ "_Z6rsFracf", (void *)&SC_frac, true },
+ // Atomics
+ { "_Z11rsAtomicIncPVi", (void *)&SC_AtomicInc, true },
+ { "_Z11rsAtomicIncPVj", (void *)&SC_AtomicInc, true },
+ { "_Z11rsAtomicDecPVi", (void *)&SC_AtomicDec, true },
+ { "_Z11rsAtomicDecPVj", (void *)&SC_AtomicDec, true },
+ { "_Z11rsAtomicAddPVii", (void *)&SC_AtomicAdd, true },
+ { "_Z11rsAtomicAddPVjj", (void *)&SC_AtomicAdd, true },
+ { "_Z11rsAtomicSubPVii", (void *)&SC_AtomicSub, true },
+ { "_Z11rsAtomicSubPVjj", (void *)&SC_AtomicSub, true },
+ { "_Z11rsAtomicAndPVii", (void *)&SC_AtomicAnd, true },
+ { "_Z11rsAtomicAndPVjj", (void *)&SC_AtomicAnd, true },
+ { "_Z10rsAtomicOrPVii", (void *)&SC_AtomicOr, true },
+ { "_Z10rsAtomicOrPVjj", (void *)&SC_AtomicOr, true },
+ { "_Z11rsAtomicXorPVii", (void *)&SC_AtomicXor, true },
+ { "_Z11rsAtomicXorPVjj", (void *)&SC_AtomicXor, true },
+ { "_Z11rsAtomicMinPVii", (void *)&SC_AtomicMin, true },
+ { "_Z11rsAtomicMinPVjj", (void *)&SC_AtomicMin, true },
+ { "_Z11rsAtomicMaxPVii", (void *)&SC_AtomicMax, true },
+ { "_Z11rsAtomicMaxPVjj", (void *)&SC_AtomicMax, true },
+ { "_Z11rsAtomicCasPViii", (void *)&SC_AtomicCas, true },
+ { "_Z11rsAtomicCasPVjjj", (void *)&SC_AtomicCas, true },
+
{ NULL, NULL, false }
};
diff --git a/libs/rs/driver/rsdRuntimeStubs.cpp b/libs/rs/driver/rsdRuntimeStubs.cpp
index 25302aa..2f9f410 100644
--- a/libs/rs/driver/rsdRuntimeStubs.cpp
+++ b/libs/rs/driver/rsdRuntimeStubs.cpp
@@ -525,10 +525,6 @@ static void SC_debugP(const char *s, const void *p) {
// ::= d # double
static RsdSymbolTable gSyms[] = {
- { "__divsi3", (void *)&SC_divsi3, true },
- { "__modsi3", (void *)&SC_modsi3, true },
- { "__udivsi3", (void *)&SC_udivsi3, true },
- { "__umodsi3", (void *)&SC_umodsi3, true },
{ "memset", (void *)&memset, true },
{ "memcpy", (void *)&memcpy, true },
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index 963a6e7..0dea971 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -103,6 +103,7 @@ ContextSetSurface {
param uint32_t width
param uint32_t height
param RsNativeWindow sur
+ sync
}
ContextDump {
diff --git a/libs/rs/scriptc/rs_math.rsh b/libs/rs/scriptc/rs_math.rsh
index 584317e..f38f72c 100644
--- a/libs/rs/scriptc/rs_math.rsh
+++ b/libs/rs/scriptc/rs_math.rsh
@@ -258,4 +258,226 @@ extern void __attribute__((overloadable))
rs_allocation output, const void * usrData,
const rs_script_call_t *);
+
+
+/**
+ * Atomic add one to the value at addr.
+ * Equal to rsAtomicAdd(addr, 1)
+ *
+ * @param addr Address of value to increment
+ *
+ * @return old value
+ */
+extern int32_t __attribute__((overloadable))
+ rsAtomicInc(volatile int32_t* addr);
+/**
+ * Atomic add one to the value at addr.
+ * Equal to rsAtomicAdd(addr, 1)
+ *
+ * @param addr Address of value to increment
+ *
+ * @return old value
+ */
+extern uint32_t __attribute__((overloadable))
+ rsAtomicInc(volatile uint32_t* addr);
+
+/**
+ * Atomic subtract one from the value at addr. Equal to rsAtomicSub(addr, 1)
+ *
+ * @param addr Address of value to decrement
+ *
+ * @return old value
+ */
+extern int32_t __attribute__((overloadable))
+ rsAtomicDec(volatile int32_t* addr);
+/**
+ * Atomic subtract one from the value at addr. Equal to rsAtomicSub(addr, 1)
+ *
+ * @param addr Address of value to decrement
+ *
+ * @return old value
+ */
+extern uint32_t __attribute__((overloadable))
+ rsAtomicDec(volatile uint32_t* addr);
+
+/**
+ * Atomic add a value to the value at addr. addr[0] += value
+ *
+ * @param addr Address of value to modify
+ * @param value Amount to add to the value at addr
+ *
+ * @return old value
+ */
+extern int32_t __attribute__((overloadable))
+ rsAtomicAdd(volatile int32_t* addr, int32_t value);
+/**
+ * Atomic add a value to the value at addr. addr[0] += value
+ *
+ * @param addr Address of value to modify
+ * @param value Amount to add to the value at addr
+ *
+ * @return old value
+ */
+extern uint32_t __attribute__((overloadable))
+ rsAtomicAdd(volatile uint32_t* addr, uint32_t value);
+
+/**
+ * Atomic Subtract a value from the value at addr. addr[0] -= value
+ *
+ * @param addr Address of value to modify
+ * @param value Amount to subtract from the value at addr
+ *
+ * @return old value
+ */
+extern int32_t __attribute__((overloadable))
+ rsAtomicSub(volatile int32_t* addr, int32_t value);
+/**
+ * Atomic Subtract a value from the value at addr. addr[0] -= value
+ *
+ * @param addr Address of value to modify
+ * @param value Amount to subtract from the value at addr
+ *
+ * @return old value
+ */
+extern uint32_t __attribute__((overloadable))
+ rsAtomicSub(volatile uint32_t* addr, uint32_t value);
+
+/**
+ * Atomic Bitwise and a value from the value at addr. addr[0] &= value
+ *
+ * @param addr Address of value to modify
+ * @param value Amount to and with the value at addr
+ *
+ * @return old value
+ */
+extern int32_t __attribute__((overloadable))
+ rsAtomicAnd(volatile int32_t* addr, int32_t value);
+/**
+ * Atomic Bitwise and a value from the value at addr. addr[0] &= value
+ *
+ * @param addr Address of value to modify
+ * @param value Amount to and with the value at addr
+ *
+ * @return old value
+ */
+extern uint32_t __attribute__((overloadable))
+ rsAtomicAnd(volatile uint32_t* addr, uint32_t value);
+
+/**
+ * Atomic Bitwise or a value from the value at addr. addr[0] |= value
+ *
+ * @param addr Address of value to modify
+ * @param value Amount to or with the value at addr
+ *
+ * @return old value
+ */
+extern int32_t __attribute__((overloadable))
+ rsAtomicOr(volatile int32_t* addr, int32_t value);
+/**
+ * Atomic Bitwise or a value from the value at addr. addr[0] |= value
+ *
+ * @param addr Address of value to modify
+ * @param value Amount to or with the value at addr
+ *
+ * @return old value
+ */
+extern uint32_t __attribute__((overloadable))
+ rsAtomicOr(volatile uint32_t* addr, uint32_t value);
+
+/**
+ * Atomic Bitwise xor a value from the value at addr. addr[0] ^= value
+ *
+ * @param addr Address of value to modify
+ * @param value Amount to xor with the value at addr
+ *
+ * @return old value
+ */
+extern uint32_t __attribute__((overloadable))
+ rsAtomicXor(volatile uint32_t* addr, uint32_t value);
+/**
+ * Atomic Bitwise xor a value from the value at addr. addr[0] ^= value
+ *
+ * @param addr Address of value to modify
+ * @param value Amount to xor with the value at addr
+ *
+ * @return old value
+ */
+extern int32_t __attribute__((overloadable))
+ rsAtomicXor(volatile int32_t* addr, int32_t value);
+
+/**
+ * Atomic Set the value at addr to the min of addr and value
+ * addr[0] = rsMin(addr[0], value)
+ *
+ * @param addr Address of value to modify
+ * @param value comparison value
+ *
+ * @return old value
+ */
+extern uint32_t __attribute__((overloadable))
+ rsAtomicMin(volatile uint32_t* addr, uint32_t value);
+/**
+ * Atomic Set the value at addr to the min of addr and value
+ * addr[0] = rsMin(addr[0], value)
+ *
+ * @param addr Address of value to modify
+ * @param value comparison value
+ *
+ * @return old value
+ */
+extern int32_t __attribute__((overloadable))
+ rsAtomicMin(volatile int32_t* addr, int32_t value);
+
+/**
+ * Atomic Set the value at addr to the max of addr and value
+ * addr[0] = rsMax(addr[0], value)
+ *
+ * @param addr Address of value to modify
+ * @param value comparison value
+ *
+ * @return old value
+ */
+extern uint32_t __attribute__((overloadable))
+ rsAtomicMax(volatile uint32_t* addr, uint32_t value);
+/**
+ * Atomic Set the value at addr to the max of addr and value
+ * addr[0] = rsMin(addr[0], value)
+ *
+ * @param addr Address of value to modify
+ * @param value comparison value
+ *
+ * @return old value
+ */
+extern int32_t __attribute__((overloadable))
+ rsAtomicMax(volatile int32_t* addr, int32_t value);
+
+/**
+ * Compare-and-set operation with a full memory barrier.
+ *
+ * If the value at addr matches compareValue then newValue is written.
+ *
+ * @param addr The address to compare and replace if the compare passes.
+ * @param compareValue The value to test addr[0] against.
+ * @param newValue The value to write if the test passes.
+ *
+ * @return old value
+ */
+extern int32_t __attribute__((overloadable))
+ rsAtomicCas(volatile int32_t* addr, int32_t compareValue, int32_t newValue);
+
+/**
+ * Compare-and-set operation with a full memory barrier.
+ *
+ * If the value at addr matches compareValue then newValue is written.
+ *
+ * @param addr The address to compare and replace if the compare passes.
+ * @param compareValue The value to test addr[0] against.
+ * @param newValue The value to write if the test passes.
+ *
+ * @return old value
+ */
+extern uint32_t __attribute__((overloadable))
+ rsAtomicCas(volatile uint32_t* addr, int32_t compareValue, int32_t newValue);
+
+
#endif
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/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/BackupData.cpp b/libs/utils/BackupData.cpp
index f963058..87912639 100644
--- a/libs/utils/BackupData.cpp
+++ b/libs/utils/BackupData.cpp
@@ -285,7 +285,8 @@ BackupDataReader::ReadNextHeader(bool* done, int* type)
break;
}
default:
- LOGD("Chunk header at %d has invalid type: 0x%08x", (int)m_pos, (int)m_header.type);
+ LOGD("Chunk header at %d has invalid type: 0x%08x",
+ (int)(m_pos - sizeof(m_header)), (int)m_header.type);
m_status = EINVAL;
}
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