diff options
178 files changed, 13296 insertions, 4595 deletions
diff --git a/build/tablet-10in-xhdpi-2048-dalvik-heap.mk b/build/tablet-10in-xhdpi-2048-dalvik-heap.mk new file mode 100644 index 0000000..eeec219 --- /dev/null +++ b/build/tablet-10in-xhdpi-2048-dalvik-heap.mk @@ -0,0 +1,22 @@ +# +# Copyright (C) 2012 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Provides overrides to configure the Dalvik heap for a standard tablet device. + +PRODUCT_PROPERTY_OVERRIDES += \ + dalvik.vm.heapstartsize=16m \ + dalvik.vm.heapgrowthlimit=192m \ + dalvik.vm.heapsize=768m diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c index 3b28b22..4bb05c4 100644 --- a/cmds/dumpstate/dumpstate.c +++ b/cmds/dumpstate/dumpstate.c @@ -88,7 +88,9 @@ static void dumpstate() { dump_file("KERNEL WAKELOCKS", "/proc/wakelocks"); + dump_file("KERNEL WAKE SOURCES", "/d/wakeup_sources"); dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state"); + dump_file("KERNEL SYNC", "/d/sync"); run_command("PROCESSES", 10, "ps", "-P", NULL); run_command("PROCESSES AND THREADS", 10, "ps", "-t", "-p", "-P", NULL); @@ -312,6 +314,14 @@ int main(int argc, char *argv[]) { int use_socket = 0; int do_fb = 0; + if (getuid() != 0) { + // Old versions of the adb client would call the + // dumpstate command directly. Newer clients + // call /system/bin/bugreport instead. If we detect + // we're being called incorrectly, then exec the + // correct program. + return execl("/system/bin/bugreport", "/system/bin/bugreport", NULL); + } ALOGI("begin\n"); signal(SIGPIPE, SIG_IGN); @@ -356,44 +366,42 @@ int main(int argc, char *argv[]) { fclose(cmdline); } - if (getuid() == 0) { - if (prctl(PR_SET_KEEPCAPS, 1) < 0) { - ALOGE("prctl(PR_SET_KEEPCAPS) failed: %s\n", strerror(errno)); - return -1; - } + if (prctl(PR_SET_KEEPCAPS, 1) < 0) { + ALOGE("prctl(PR_SET_KEEPCAPS) failed: %s\n", strerror(errno)); + return -1; + } - /* switch to non-root user and group */ - gid_t groups[] = { AID_LOG, AID_SDCARD_R, AID_SDCARD_RW, - AID_MOUNT, AID_INET, AID_NET_BW_STATS }; - if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) { - ALOGE("Unable to setgroups, aborting: %s\n", strerror(errno)); - return -1; - } - if (setgid(AID_SHELL) != 0) { - ALOGE("Unable to setgid, aborting: %s\n", strerror(errno)); - return -1; - } - if (setuid(AID_SHELL) != 0) { - ALOGE("Unable to setuid, aborting: %s\n", strerror(errno)); - return -1; - } + /* switch to non-root user and group */ + gid_t groups[] = { AID_LOG, AID_SDCARD_R, AID_SDCARD_RW, + AID_MOUNT, AID_INET, AID_NET_BW_STATS }; + if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) { + ALOGE("Unable to setgroups, aborting: %s\n", strerror(errno)); + return -1; + } + if (setgid(AID_SHELL) != 0) { + ALOGE("Unable to setgid, aborting: %s\n", strerror(errno)); + return -1; + } + if (setuid(AID_SHELL) != 0) { + ALOGE("Unable to setuid, aborting: %s\n", strerror(errno)); + return -1; + } - struct __user_cap_header_struct capheader; - struct __user_cap_data_struct capdata[2]; - memset(&capheader, 0, sizeof(capheader)); - memset(&capdata, 0, sizeof(capdata)); - capheader.version = _LINUX_CAPABILITY_VERSION_3; - capheader.pid = 0; - - capdata[CAP_TO_INDEX(CAP_SYSLOG)].permitted = CAP_TO_MASK(CAP_SYSLOG); - capdata[CAP_TO_INDEX(CAP_SYSLOG)].effective = CAP_TO_MASK(CAP_SYSLOG); - capdata[0].inheritable = 0; - capdata[1].inheritable = 0; - - if (capset(&capheader, &capdata[0]) < 0) { - ALOGE("capset failed: %s\n", strerror(errno)); - return -1; - } + struct __user_cap_header_struct capheader; + struct __user_cap_data_struct capdata[2]; + memset(&capheader, 0, sizeof(capheader)); + memset(&capdata, 0, sizeof(capdata)); + capheader.version = _LINUX_CAPABILITY_VERSION_3; + capheader.pid = 0; + + capdata[CAP_TO_INDEX(CAP_SYSLOG)].permitted = CAP_TO_MASK(CAP_SYSLOG); + capdata[CAP_TO_INDEX(CAP_SYSLOG)].effective = CAP_TO_MASK(CAP_SYSLOG); + capdata[0].inheritable = 0; + capdata[1].inheritable = 0; + + if (capset(&capheader, &capdata[0]) < 0) { + ALOGE("capset failed: %s\n", strerror(errno)); + return -1; } char path[PATH_MAX], tmp_path[PATH_MAX]; diff --git a/cmds/sensorservice/Android.mk b/cmds/sensorservice/Android.mk new file mode 100644 index 0000000..0811be5 --- /dev/null +++ b/cmds/sensorservice/Android.mk @@ -0,0 +1,19 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + main_sensorservice.cpp + +LOCAL_SHARED_LIBRARIES := \ + libsensorservice \ + libbinder \ + libutils + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/../../services/sensorservice + +LOCAL_MODULE_TAGS := optional + +LOCAL_MODULE:= sensorservice + +include $(BUILD_EXECUTABLE) diff --git a/cmds/sensorservice/main_sensorservice.cpp b/cmds/sensorservice/main_sensorservice.cpp new file mode 100644 index 0000000..8610627 --- /dev/null +++ b/cmds/sensorservice/main_sensorservice.cpp @@ -0,0 +1,25 @@ +/* + * 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. + */ + +#include <binder/BinderService.h> +#include <SensorService.h> + +using namespace android; + +int main(int argc, char** argv) { + SensorService::publishAndJoinThreadPool(); + return 0; +} diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h index 33b2f00..877b17c 100644 --- a/include/binder/Parcel.h +++ b/include/binder/Parcel.h @@ -22,10 +22,12 @@ #include <utils/RefBase.h> #include <utils/String16.h> #include <utils/Vector.h> +#include <utils/Flattenable.h> // --------------------------------------------------------------------------- namespace android { +template <typename T> class LightFlattenable; class Flattenable; class IBinder; class IPCThreadState; @@ -102,6 +104,10 @@ public: status_t writeWeakBinder(const wp<IBinder>& val); status_t write(const Flattenable& val); + template<typename T> + status_t write(const LightFlattenable<T>& val); + + // Place a native_handle into the parcel (the native_handle's file- // descriptors are dup'ed, so it is safe to delete the native_handle // when this function returns). @@ -153,6 +159,9 @@ public: wp<IBinder> readWeakBinder() const; status_t read(Flattenable& val) const; + template<typename T> + status_t read(LightFlattenable<T>& val) const; + // Like Parcel.java's readExceptionCode(). Reads the first int32 // off of a Parcel's header, returning 0 or the negative error // code on exceptions, but also deals with skipping over rich @@ -267,6 +276,40 @@ public: // --------------------------------------------------------------------------- +template<typename T> +status_t Parcel::write(const LightFlattenable<T>& val) { + size_t size(val.getSize()); + if (!val.isFixedSize()) { + status_t err = writeInt32(size); + if (err != NO_ERROR) { + return err; + } + } + void* buffer = writeInplace(size); + return buffer == NULL ? NO_MEMORY : + val.flatten(buffer); +} + +template<typename T> +status_t Parcel::read(LightFlattenable<T>& val) const { + size_t size; + if (val.isFixedSize()) { + size = val.getSize(); + } else { + int32_t s; + status_t err = readInt32(&s); + if (err != NO_ERROR) { + return err; + } + size = s; + } + void const* buffer = readInplace(size); + return buffer == NULL ? NO_MEMORY : + val.unflatten(buffer, size); +} + +// --------------------------------------------------------------------------- + inline TextOutput& operator<<(TextOutput& to, const Parcel& parcel) { parcel.print(to); diff --git a/include/binder/PermissionCache.h b/include/binder/PermissionCache.h index 1171d48..bcdf0c2 100644 --- a/include/binder/PermissionCache.h +++ b/include/binder/PermissionCache.h @@ -22,6 +22,7 @@ #include <utils/String16.h> #include <utils/Singleton.h> +#include <utils/SortedVector.h> namespace android { // --------------------------------------------------------------------------- diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h index 1c80d0c..85d8fb6 100644 --- a/include/gui/BufferQueue.h +++ b/include/gui/BufferQueue.h @@ -23,6 +23,7 @@ #include <gui/IGraphicBufferAlloc.h> #include <gui/ISurfaceTexture.h> +#include <ui/Fence.h> #include <ui/GraphicBuffer.h> #include <utils/String8.h> @@ -96,7 +97,9 @@ public: // allowSynchronousMode specifies whether or not synchronous mode can be // enabled. // bufferCount sets the minimum number of undequeued buffers for this queue - BufferQueue( bool allowSynchronousMode = true, int bufferCount = MIN_UNDEQUEUED_BUFFERS); + BufferQueue(bool allowSynchronousMode = true, + int bufferCount = MIN_UNDEQUEUED_BUFFERS, + const sp<IGraphicBufferAlloc>& allocator = NULL); virtual ~BufferQueue(); virtual int query(int what, int* value); @@ -113,12 +116,18 @@ public: // pointed to by the buf argument and a status of OK is returned. If no // slot is available then a status of -EBUSY is returned and buf is // unmodified. + // + // The fence parameter will be updated to hold the fence associated with + // the buffer. The contents of the buffer must not be overwritten until the + // fence signals. If the fence is NULL, the buffer may be written + // immediately. + // // The width and height parameters must be no greater than the minimum of // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv). // An error due to invalid dimensions might not be reported until // updateTexImage() is called. - virtual status_t dequeueBuffer(int *buf, uint32_t width, uint32_t height, - uint32_t format, uint32_t usage); + virtual status_t dequeueBuffer(int *buf, sp<Fence>& fence, + uint32_t width, uint32_t height, uint32_t format, uint32_t usage); // queueBuffer returns a filled buffer to the BufferQueue. In addition, a // timestamp must be provided for the buffer. The timestamp is in @@ -128,7 +137,7 @@ public: virtual status_t queueBuffer(int buf, const QueueBufferInput& input, QueueBufferOutput* output); - virtual void cancelBuffer(int buf); + virtual void cancelBuffer(int buf, sp<Fence> fence); // setSynchronousMode set whether dequeueBuffer is synchronous or // asynchronous. In synchronous mode, dequeueBuffer blocks until @@ -193,6 +202,9 @@ public: // mBuf is the slot index of this buffer int mBuf; + + // mFence is a fence that will signal when the buffer is idle. + sp<Fence> mFence; }; // The following public functions is the consumer facing interface @@ -209,9 +221,15 @@ public: // releaseBuffer releases a buffer slot from the consumer back to the // BufferQueue pending a fence sync. // + // If releaseBuffer returns STALE_BUFFER_SLOT, then the consumer must free + // any references to the just-released buffer that it might have, as if it + // had received a onBuffersReleased() call with a mask set for the released + // buffer. + // // Note that the dependencies on EGL will be removed once we switch to using // the Android HW Sync HAL. - status_t releaseBuffer(int buf, EGLDisplay display, EGLSyncKHR fence); + status_t releaseBuffer(int buf, EGLDisplay display, EGLSyncKHR fence, + const sp<Fence>& releaseFence); // consumerConnect connects a consumer to the BufferQueue. Only one // consumer may be connected, and when that consumer disconnects the @@ -292,7 +310,7 @@ private: mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mTimestamp(0), mFrameNumber(0), - mFence(EGL_NO_SYNC_KHR), + mEglFence(EGL_NO_SYNC_KHR), mAcquireCalled(false), mNeedsCleanupOnRelease(false) { mCrop.makeInvalid(); @@ -365,11 +383,22 @@ private: // mFrameNumber is the number of the queued frame for this slot. uint64_t mFrameNumber; - // mFence is the EGL sync object that must signal before the buffer + // mEglFence is the EGL sync object that must signal before the buffer // associated with this buffer slot may be dequeued. It is initialized // to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based // on a compile-time option) set to a new sync object in updateTexImage. - EGLSyncKHR mFence; + EGLSyncKHR mEglFence; + + // mFence is a fence which will signal when work initiated by the + // previous owner of the buffer is finished. When the buffer is FREE, + // the fence indicates when the consumer has finished reading + // from the buffer, or when the producer has finished writing if it + // called cancelBuffer after queueing some writes. When the buffer is + // QUEUED, it indicates when the producer has finished filling the + // buffer. When the buffer is DEQUEUED or ACQUIRED, the fence has been + // passed to the consumer or producer along with ownership of the + // buffer, and mFence is empty. + sp<Fence> mFence; // Indicates whether this buffer has been seen by a consumer yet bool mAcquireCalled; @@ -393,10 +422,6 @@ private: // in requestBuffers() if a width and height of zero is specified. uint32_t mDefaultHeight; - // mPixelFormat holds the pixel format of allocated buffers. It is used - // in requestBuffers() if a format of zero is specified. - uint32_t mPixelFormat; - // mMinUndequeuedBuffers is a constraint on the number of buffers // not dequeued at any time int mMinUndequeuedBuffers; diff --git a/include/gui/ConsumerBase.h b/include/gui/ConsumerBase.h new file mode 100644 index 0000000..1f643a3 --- /dev/null +++ b/include/gui/ConsumerBase.h @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_GUI_CONSUMERBASE_H +#define ANDROID_GUI_CONSUMERBASE_H + +#include <gui/BufferQueue.h> + +#include <ui/GraphicBuffer.h> + +#include <utils/String8.h> +#include <utils/Vector.h> +#include <utils/threads.h> + +namespace android { +// ---------------------------------------------------------------------------- + +class String8; + +// ConsumerBase is a base class for BufferQueue consumer end-points. It +// handles common tasks like management of the connection to the BufferQueue +// and the buffer pool. +class ConsumerBase : public virtual RefBase, + protected BufferQueue::ConsumerListener { +public: + struct FrameAvailableListener : public virtual RefBase { + // onFrameAvailable() is called each time an additional frame becomes + // available for consumption. This means that frames that are queued + // while in asynchronous mode only trigger the callback if no previous + // frames are pending. Frames queued while in synchronous mode always + // trigger the callback. + // + // This is called without any lock held and can be called concurrently + // by multiple threads. + virtual void onFrameAvailable() = 0; + }; + + virtual ~ConsumerBase(); + + // abandon frees all the buffers and puts the ConsumerBase into the + // 'abandoned' state. Once put in this state the ConsumerBase can never + // leave it. When in the 'abandoned' state, all methods of the + // ISurfaceTexture interface will fail with the NO_INIT error. + // + // Note that while calling this method causes all the buffers to be freed + // from the perspective of the the ConsumerBase, if there are additional + // references on the buffers (e.g. if a buffer is referenced by a client + // or by OpenGL ES as a texture) then those buffer will remain allocated. + void abandon(); + + // set the name of the ConsumerBase that will be used to identify it in + // log messages. + void setName(const String8& name); + + // getBufferQueue returns the BufferQueue object to which this + // ConsumerBase is connected. + sp<BufferQueue> getBufferQueue() const; + + // dump writes the current state to a string. These methods should NOT be + // overridden by child classes. Instead they should override the + // dumpLocked method, which is called by these methods after locking the + // mutex. + void dump(String8& result) const; + void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const; + + // setFrameAvailableListener sets the listener object that will be notified + // when a new frame becomes available. + void setFrameAvailableListener(const sp<FrameAvailableListener>& listener); + +private: + ConsumerBase(const ConsumerBase&); + void operator=(const ConsumerBase&); + +protected: + + // TODO: Fix this comment + // ConsumerBase constructs a new ConsumerBase object. tex indicates the + // name of the OpenGL ES texture to which images are to be streamed. + // allowSynchronousMode specifies whether or not synchronous mode can be + // enabled. texTarget specifies the OpenGL ES texture target to which the + // texture will be bound in updateTexImage. useFenceSync specifies whether + // fences should be used to synchronize access to buffers if that behavior + // is enabled at compile-time. A custom bufferQueue can be specified + // if behavior for queue/dequeue/connect etc needs to be customized. + // Otherwise a default BufferQueue will be created and used. + // + // For legacy reasons, the ConsumerBase is created in a state where it is + // considered attached to an OpenGL ES context for the purposes of the + // attachToContext and detachFromContext methods. However, despite being + // considered "attached" to a context, the specific OpenGL ES context + // doesn't get latched until the first call to updateTexImage. After that + // point, all calls to updateTexImage must be made with the same OpenGL ES + // context current. + // + // A ConsumerBase may be detached from one OpenGL ES context and then + // attached to a different context using the detachFromContext and + // attachToContext methods, respectively. The intention of these methods is + // purely to allow a ConsumerBase to be transferred from one consumer + // context to another. If such a transfer is not needed there is no + // requirement that either of these methods be called. + ConsumerBase(const sp<BufferQueue> &bufferQueue); + + // Implementation of the BufferQueue::ConsumerListener interface. These + // calls are used to notify the ConsumerBase of asynchronous events in the + // BufferQueue. + virtual void onFrameAvailable(); + virtual void onBuffersReleased(); + + // freeBufferLocked frees up the given buffer slot. If the slot has been + // initialized this will release the reference to the GraphicBuffer in that + // slot and destroy the EGLImage in that slot. Otherwise it has no effect. + // + // This method must be called with mMutex locked. + virtual void freeBufferLocked(int slotIndex); + + // abandonLocked puts the BufferQueue into the abandoned state, causing + // all future operations on it to fail. This method rather than the public + // abandon method should be overridden by child classes to add abandon- + // time behavior. + // + // This method must be called with mMutex locked. + virtual void abandonLocked(); + + virtual void dumpLocked(String8& result, const char* prefix, char* buffer, + size_t SIZE) const; + + // acquireBufferLocked fetches the next buffer from the BufferQueue and + // updates the buffer slot for the buffer returned. + virtual status_t acquireBufferLocked(BufferQueue::BufferItem *item); + + // releaseBufferLocked relinquishes control over a buffer, returning that + // control to the BufferQueue. + virtual status_t releaseBufferLocked(int buf, EGLDisplay display, + EGLSyncKHR eglFence, const sp<Fence>& fence); + + // Slot contains the information and object references that + // ConsumerBase maintains about a BufferQueue buffer slot. + struct Slot { + // mGraphicBuffer is the Gralloc buffer store in the slot or NULL if + // no Gralloc buffer is in the slot. + sp<GraphicBuffer> mGraphicBuffer; + + // mFence is a fence which will signal when the buffer associated with + // this buffer slot is no longer being used by the consumer and can be + // overwritten. The buffer can be dequeued before the fence signals; + // the producer is responsible for delaying writes until it signals. + sp<Fence> mFence; + }; + + // mSlots stores the buffers that have been allocated by the BufferQueue + // for each buffer slot. It is initialized to null pointers, and gets + // filled in with the result of BufferQueue::acquire when the + // client dequeues a buffer from a + // slot that has not yet been used. The buffer allocated to a slot will also + // be replaced if the requested buffer usage or geometry differs from that + // of the buffer allocated to a slot. + Slot mSlots[BufferQueue::NUM_BUFFER_SLOTS]; + + // mAbandoned indicates that the BufferQueue will no longer be used to + // consume images buffers pushed to it using the ISurfaceTexture + // interface. It is initialized to false, and set to true in the abandon + // method. A BufferQueue that has been abandoned will return the NO_INIT + // error from all IConsumerBase methods capable of returning an error. + bool mAbandoned; + + // mName is a string used to identify the ConsumerBase in log messages. + // It can be set by the setName method. + String8 mName; + + // mFrameAvailableListener is the listener object that will be called when a + // new frame becomes available. If it is not NULL it will be called from + // queueBuffer. + sp<FrameAvailableListener> mFrameAvailableListener; + + // The ConsumerBase has-a BufferQueue and is responsible for creating this object + // if none is supplied + sp<BufferQueue> mBufferQueue; + + // mMutex is the mutex used to prevent concurrent access to the member + // variables of ConsumerBase objects. It must be locked whenever the + // member variables are accessed. + mutable Mutex mMutex; +}; + +// ---------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_GUI_CONSUMERBASE_H diff --git a/include/gui/CpuConsumer.h b/include/gui/CpuConsumer.h new file mode 100644 index 0000000..a50a1de --- /dev/null +++ b/include/gui/CpuConsumer.h @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_GUI_CPUCONSUMER_H +#define ANDROID_GUI_CPUCONSUMER_H + +#include <gui/BufferQueue.h> + +#include <ui/GraphicBuffer.h> + +#include <utils/String8.h> +#include <utils/Vector.h> +#include <utils/threads.h> + +#define ANDROID_GRAPHICS_CPUCONSUMER_JNI_ID "mCpuConsumer" + +namespace android { + +/** + * CpuConsumer is a BufferQueue consumer endpoint that allows direct CPU + * access to the underlying gralloc buffers provided by BufferQueue. Multiple + * buffers may be acquired by it at once, to be used concurrently by the + * CpuConsumer owner. Sets gralloc usage flags to be software-read-only. + * This queue is synchronous by default. + */ + +class CpuConsumer: public virtual RefBase, + protected BufferQueue::ConsumerListener +{ + public: + struct FrameAvailableListener : public virtual RefBase { + // onFrameAvailable() is called each time an additional frame becomes + // available for consumption. A new frame queued will always trigger the + // callback, whether the queue is empty or not. + // + // This is called without any lock held and can be called concurrently + // by multiple threads. + virtual void onFrameAvailable() = 0; + }; + + struct LockedBuffer { + uint8_t *data; + uint32_t width; + uint32_t height; + PixelFormat format; + uint32_t stride; + Rect crop; + uint32_t transform; + uint32_t scalingMode; + int64_t timestamp; + uint64_t frameNumber; + }; + + // Create a new CPU consumer. The maxLockedBuffers parameter specifies + // how many buffers can be locked for user access at the same time. + CpuConsumer(uint32_t maxLockedBuffers); + + virtual ~CpuConsumer(); + + // set the name of the CpuConsumer that will be used to identify it in + // log messages. + void setName(const String8& name); + + // Gets the next graphics buffer from the producer and locks it for CPU use, + // filling out the passed-in locked buffer structure with the native pointer + // and metadata. Returns BAD_VALUE if no new buffer is available, and + // INVALID_OPERATION if the maximum number of buffers is already locked. + // + // Only a fixed number of buffers can be locked at a time, determined by the + // construction-time maxLockedBuffers parameter. If INVALID_OPERATION is + // returned by lockNextBuffer, then old buffers must be returned to the queue + // by calling unlockBuffer before more buffers can be acquired. + status_t lockNextBuffer(LockedBuffer *nativeBuffer); + + // Returns a locked buffer to the queue, allowing it to be reused. Since + // only a fixed number of buffers may be locked at a time, old buffers must + // be released by calling unlockBuffer to ensure new buffers can be acquired by + // lockNextBuffer. + status_t unlockBuffer(const LockedBuffer &nativeBuffer); + + // setFrameAvailableListener sets the listener object that will be notified + // when a new frame becomes available. + void setFrameAvailableListener(const sp<FrameAvailableListener>& listener); + + sp<ISurfaceTexture> getProducerInterface() const { return mBufferQueue; } + protected: + + // Implementation of the BufferQueue::ConsumerListener interface. These + // calls are used to notify the CpuConsumer of asynchronous events in the + // BufferQueue. + virtual void onFrameAvailable(); + virtual void onBuffersReleased(); + + private: + // Free local buffer state + status_t freeBufferLocked(int buf); + + // Maximum number of buffers that can be locked at a time + uint32_t mMaxLockedBuffers; + + // mName is a string used to identify the SurfaceTexture in log messages. + // It can be set by the setName method. + String8 mName; + + // mFrameAvailableListener is the listener object that will be called when a + // new frame becomes available. If it is not NULL it will be called from + // queueBuffer. + sp<FrameAvailableListener> mFrameAvailableListener; + + // Underlying buffer queue + sp<BufferQueue> mBufferQueue; + + // Array for caching buffers from the buffer queue + sp<GraphicBuffer> mBufferSlot[BufferQueue::NUM_BUFFER_SLOTS]; + // Array for tracking pointers passed to the consumer, matching the + // mBufferSlot indexing + void *mBufferPointers[BufferQueue::NUM_BUFFER_SLOTS]; + // Count of currently locked buffers + uint32_t mCurrentLockedBuffers; + + // mMutex is the mutex used to prevent concurrent access to the member + // variables of CpuConsumer objects. It must be locked whenever the + // member variables are accessed. + mutable Mutex mMutex; +}; + +} // namespace android + +#endif // ANDROID_GUI_CPUCONSUMER_H diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h index 7320e4d..9ab35b1 100644 --- a/include/gui/ISurfaceComposer.h +++ b/include/gui/ISurfaceComposer.h @@ -34,66 +34,23 @@ namespace android { // ---------------------------------------------------------------------------- class ComposerState; +class DisplayState; +class DisplayInfo; class IDisplayEventConnection; class IMemoryHeap; -class ISurfaceComposer : public IInterface -{ +class ISurfaceComposer: public IInterface { public: DECLARE_META_INTERFACE(SurfaceComposer); - enum { // (keep in sync with Surface.java) - eHidden = 0x00000004, - eDestroyBackbuffer = 0x00000020, - eSecure = 0x00000080, - eNonPremultiplied = 0x00000100, - eOpaque = 0x00000400, - eProtectedByApp = 0x00000800, - eProtectedByDRM = 0x00001000, - - eFXSurfaceNormal = 0x00000000, - eFXSurfaceBlur = 0x00010000, - eFXSurfaceDim = 0x00020000, - eFXSurfaceScreenshot= 0x00030000, - eFXSurfaceMask = 0x000F0000, - }; - - enum { - ePositionChanged = 0x00000001, - eLayerChanged = 0x00000002, - eSizeChanged = 0x00000004, - eAlphaChanged = 0x00000008, - eMatrixChanged = 0x00000010, - eTransparentRegionChanged = 0x00000020, - eVisibilityChanged = 0x00000040, - eFreezeTintChanged = 0x00000080, - eCropChanged = 0x00000100, - }; - + // flags for setTransactionState() enum { - eLayerHidden = 0x01, - eLayerFrozen = 0x02, - eLayerDither = 0x04, - eLayerFilter = 0x08, - eLayerBlurFreeze = 0x10 + eSynchronous = 0x01, }; enum { - eOrientationDefault = 0, - eOrientation90 = 1, - eOrientation180 = 2, - eOrientation270 = 3, - eOrientationUnchanged = 4, - eOrientationSwapMask = 0x01 - }; - - enum { - eSynchronous = 0x01, - }; - - enum { - eElectronBeamAnimationOn = 0x01, - eElectronBeamAnimationOff = 0x10 + eDisplayIdMain = 0, + eDisplayIdHdmi = 1 }; /* create connection with surface flinger, requires @@ -105,46 +62,59 @@ public: */ virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc() = 0; - /* retrieve the control block */ - virtual sp<IMemoryHeap> getCblk() const = 0; + /* return an IDisplayEventConnection */ + virtual sp<IDisplayEventConnection> createDisplayEventConnection() = 0; + + /* create a display with given id. + * requires ACCESS_SURFACE_FLINGER permission. + */ + virtual sp<IBinder> createDisplay() = 0; + + /* get the token for the existing default displays. possible values + * for id are eDisplayIdMain and eDisplayIdHdmi. + */ + virtual sp<IBinder> getBuiltInDisplay(int32_t id) = 0; /* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */ virtual void setTransactionState(const Vector<ComposerState>& state, - int orientation, uint32_t flags) = 0; + const Vector<DisplayState>& displays, uint32_t flags) = 0; /* signal that we're done booting. * Requires ACCESS_SURFACE_FLINGER permission */ virtual void bootFinished() = 0; + /* verify that an ISurfaceTexture was created by SurfaceFlinger. + */ + virtual bool authenticateSurfaceTexture( + const sp<ISurfaceTexture>& surface) const = 0; + /* Capture the specified screen. requires READ_FRAME_BUFFER permission * This function will fail if there is a secure window on screen. */ - virtual status_t captureScreen(DisplayID dpy, - sp<IMemoryHeap>* heap, + virtual status_t captureScreen(DisplayID dpy, sp<IMemoryHeap>* heap, uint32_t* width, uint32_t* height, PixelFormat* format, - uint32_t reqWidth, uint32_t reqHeight, - uint32_t minLayerZ, uint32_t maxLayerZ) = 0; + uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, + uint32_t maxLayerZ) = 0; - /* triggers screen off animation */ - virtual status_t turnElectronBeamOff(int32_t mode) = 0; - /* triggers screen on animation */ - virtual status_t turnElectronBeamOn(int32_t mode) = 0; + /* triggers screen off and waits for it to complete */ + virtual void blank() = 0; - /* verify that an ISurfaceTexture was created by SurfaceFlinger. - */ - virtual bool authenticateSurfaceTexture( - const sp<ISurfaceTexture>& surface) const = 0; + /* triggers screen on and waits for it to complete */ + virtual void unblank() = 0; - /* return an IDisplayEventConnection */ - virtual sp<IDisplayEventConnection> createDisplayEventConnection() = 0; + /* returns information about a physical screen. This is intended to be + * used by low-level native tests */ + virtual status_t getDisplayInfo(DisplayID dpy, DisplayInfo* info) = 0; + + /* connects to an external display */ + virtual void connectDisplay(const sp<ISurfaceTexture> display) = 0; }; // ---------------------------------------------------------------------------- -class BnSurfaceComposer : public BnInterface<ISurfaceComposer> -{ +class BnSurfaceComposer: public BnInterface<ISurfaceComposer> { public: enum { // Note: BOOT_FINISHED must remain this value, it is called from @@ -152,20 +122,20 @@ public: BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION, CREATE_CONNECTION, CREATE_GRAPHIC_BUFFER_ALLOC, - GET_CBLK, + CREATE_DISPLAY_EVENT_CONNECTION, + CREATE_DISPLAY, + GET_BUILT_IN_DISPLAY, SET_TRANSACTION_STATE, - SET_ORIENTATION, - CAPTURE_SCREEN, - TURN_ELECTRON_BEAM_OFF, - TURN_ELECTRON_BEAM_ON, AUTHENTICATE_SURFACE, - CREATE_DISPLAY_EVENT_CONNECTION, + CAPTURE_SCREEN, + BLANK, + UNBLANK, + GET_DISPLAY_INFO, + CONNECT_DISPLAY, }; - virtual status_t onTransact( uint32_t code, - const Parcel& data, - Parcel* reply, - uint32_t flags = 0); + virtual status_t onTransact(uint32_t code, const Parcel& data, + Parcel* reply, uint32_t flags = 0); }; // ---------------------------------------------------------------------------- diff --git a/include/gui/ISurfaceComposerClient.h b/include/gui/ISurfaceComposerClient.h index c793933..259c1df 100644 --- a/include/gui/ISurfaceComposerClient.h +++ b/include/gui/ISurfaceComposerClient.h @@ -42,9 +42,26 @@ class ISurfaceComposerClient : public IInterface public: DECLARE_META_INTERFACE(SurfaceComposerClient); + // flags for createSurface() + enum { // (keep in sync with Surface.java) + eHidden = 0x00000004, + eDestroyBackbuffer = 0x00000020, + eSecure = 0x00000080, + eNonPremultiplied = 0x00000100, + eOpaque = 0x00000400, + eProtectedByApp = 0x00000800, + eProtectedByDRM = 0x00001000, + + eFXSurfaceNormal = 0x00000000, + eFXSurfaceBlur = 0x00010000, // deprecated, same as Dim + eFXSurfaceDim = 0x00020000, + eFXSurfaceScreenshot= 0x00030000, + eFXSurfaceMask = 0x000F0000, + }; + struct surface_data_t { - int32_t token; - int32_t identity; + int32_t token; + int32_t identity; status_t readFromParcel(const Parcel& parcel); status_t writeToParcel(Parcel* parcel) const; }; @@ -52,29 +69,22 @@ public: /* * Requires ACCESS_SURFACE_FLINGER permission */ - virtual sp<ISurface> createSurface( surface_data_t* data, - const String8& name, - DisplayID display, - uint32_t w, - uint32_t h, - PixelFormat format, - uint32_t flags) = 0; + virtual sp<ISurface> createSurface(surface_data_t* data, + const String8& name, DisplayID display, uint32_t w, uint32_t h, + PixelFormat format, uint32_t flags) = 0; /* * Requires ACCESS_SURFACE_FLINGER permission */ - virtual status_t destroySurface(SurfaceID sid) = 0; + virtual status_t destroySurface(SurfaceID sid) = 0; }; // ---------------------------------------------------------------------------- -class BnSurfaceComposerClient : public BnInterface<ISurfaceComposerClient> -{ +class BnSurfaceComposerClient: public BnInterface<ISurfaceComposerClient> { public: - virtual status_t onTransact( uint32_t code, - const Parcel& data, - Parcel* reply, - uint32_t flags = 0); + virtual status_t onTransact(uint32_t code, const Parcel& data, + Parcel* reply, uint32_t flags = 0); }; // ---------------------------------------------------------------------------- diff --git a/include/gui/ISurfaceTexture.h b/include/gui/ISurfaceTexture.h index 1e33764..8b4025d 100644 --- a/include/gui/ISurfaceTexture.h +++ b/include/gui/ISurfaceTexture.h @@ -25,6 +25,7 @@ #include <binder/IInterface.h> +#include <ui/Fence.h> #include <ui/GraphicBuffer.h> #include <ui/Rect.h> @@ -67,8 +68,13 @@ protected: // in the contents of its associated buffer contents and call queueBuffer. // If dequeueBuffer return BUFFER_NEEDS_REALLOCATION, the client is // expected to call requestBuffer immediately. - virtual status_t dequeueBuffer(int *slot, uint32_t w, uint32_t h, - uint32_t format, uint32_t usage) = 0; + // + // The fence parameter will be updated to hold the fence associated with + // the buffer. The contents of the buffer must not be overwritten until the + // fence signals. If the fence is NULL, the buffer may be written + // immediately. + virtual status_t dequeueBuffer(int *slot, sp<Fence>& fence, + uint32_t w, uint32_t h, uint32_t format, uint32_t usage) = 0; // queueBuffer indicates that the client has finished filling in the // contents of the buffer associated with slot and transfers ownership of @@ -83,24 +89,37 @@ protected: // and height of the window and current transform applied to buffers, // respectively. - // QueueBufferInput must be a POD structure - struct QueueBufferInput { + struct QueueBufferInput : public Flattenable { + inline QueueBufferInput(const Parcel& parcel); inline QueueBufferInput(int64_t timestamp, - const Rect& crop, int scalingMode, uint32_t transform) + const Rect& crop, int scalingMode, uint32_t transform, + sp<Fence> fence) : timestamp(timestamp), crop(crop), scalingMode(scalingMode), - transform(transform) { } + transform(transform), fence(fence) { } inline void deflate(int64_t* outTimestamp, Rect* outCrop, - int* outScalingMode, uint32_t* outTransform) const { + int* outScalingMode, uint32_t* outTransform, + sp<Fence>* outFence) const { *outTimestamp = timestamp; *outCrop = crop; *outScalingMode = scalingMode; *outTransform = transform; + *outFence = fence; } + + // Flattenable interface + virtual size_t getFlattenedSize() const; + virtual size_t getFdCount() const; + virtual status_t flatten(void* buffer, size_t size, + int fds[], size_t count) const; + virtual status_t unflatten(void const* buffer, size_t size, + int fds[], size_t count); + private: int64_t timestamp; Rect crop; int scalingMode; uint32_t transform; + sp<Fence> fence; }; // QueueBufferOutput must be a POD structure @@ -135,7 +154,7 @@ protected: // cancelBuffer indicates that the client does not wish to fill in the // buffer associated with slot and transfers ownership of the slot back to // the server. - virtual void cancelBuffer(int slot) = 0; + virtual void cancelBuffer(int slot, sp<Fence> fence) = 0; // query retrieves some information for this surface // 'what' tokens allowed are that of android_natives.h diff --git a/include/gui/Sensor.h b/include/gui/Sensor.h index e59757a..2af2307 100644 --- a/include/gui/Sensor.h +++ b/include/gui/Sensor.h @@ -41,7 +41,7 @@ class Parcel; // ---------------------------------------------------------------------------- -class Sensor : public ASensor, public Flattenable +class Sensor : public ASensor, public LightFlattenable<Sensor> { public: enum { @@ -54,7 +54,7 @@ public: Sensor(); Sensor(struct sensor_t const* hwSensor); - virtual ~Sensor(); + ~Sensor(); const String8& getName() const; const String8& getVendor() const; @@ -68,13 +68,11 @@ public: nsecs_t getMinDelayNs() const; int32_t getVersion() const; - // Flattenable interface - virtual size_t getFlattenedSize() const; - virtual size_t getFdCount() const; - virtual status_t flatten(void* buffer, size_t size, - int fds[], size_t count) const; - virtual status_t unflatten(void const* buffer, size_t size, - int fds[], size_t count); + // LightFlattenable protocol + inline bool isFixedSize() const { return false; } + size_t getSize() const; + status_t flatten(void* buffer) const; + status_t unflatten(void const* buffer, size_t size); private: String8 mName; diff --git a/include/gui/Surface.h b/include/gui/Surface.h index 50bdf71..7b8873a 100644 --- a/include/gui/Surface.h +++ b/include/gui/Surface.h @@ -65,13 +65,10 @@ public: status_t setSize(uint32_t w, uint32_t h); status_t hide(); status_t show(int32_t layer = -1); - status_t freeze(); - status_t unfreeze(); status_t setFlags(uint32_t flags, uint32_t mask); status_t setTransparentRegionHint(const Region& transparent); status_t setAlpha(float alpha=1.0f); status_t setMatrix(float dsdx, float dtdx, float dsdy, float dtdy); - status_t setFreezeTint(uint32_t tint); status_t setCrop(const Rect& crop); static status_t writeSurfaceToParcel( diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h index 3bd10de..5776038 100644 --- a/include/gui/SurfaceComposerClient.h +++ b/include/gui/SurfaceComposerClient.h @@ -59,6 +59,13 @@ public: // Forcibly remove connection before all references have gone away. void dispose(); + // callback when the composer is dies + status_t linkToComposerDeath(const sp<IBinder::DeathRecipient>& recipient, + void* cookie = NULL, uint32_t flags = 0); + + // Get information about a display + static status_t getDisplayInfo(DisplayID dpy, DisplayInfo* info); + // ------------------------------------------------------------------------ // surface creation / destruction @@ -80,56 +87,47 @@ public: uint32_t flags = 0 // usage flags ); + static sp<IBinder> createDisplay(); // ------------------------------------------------------------------------ // Composer parameters // All composer parameters must be changed within a transaction // several surfaces can be updated in one transaction, all changes are // committed at once when the transaction is closed. - // closeGlobalTransaction() usually requires an IPC with the server. + // closeGlobalTransaction() requires an IPC with the server. //! Open a composer transaction on all active SurfaceComposerClients. static void openGlobalTransaction(); //! Close a composer transaction on all active SurfaceComposerClients. static void closeGlobalTransaction(bool synchronous = false); - - //! Freeze the specified display but not transactions. - static status_t freezeDisplay(DisplayID dpy, uint32_t flags = 0); - - //! Resume updates on the specified display. - static status_t unfreezeDisplay(DisplayID dpy, uint32_t flags = 0); //! Set the orientation of the given display static int setOrientation(DisplayID dpy, int orientation, uint32_t flags); - // Query the number of displays - static ssize_t getNumberOfDisplays(); - - // Get information about a display - static status_t getDisplayInfo(DisplayID dpy, DisplayInfo* info); - static ssize_t getDisplayWidth(DisplayID dpy); - static ssize_t getDisplayHeight(DisplayID dpy); - static ssize_t getDisplayOrientation(DisplayID dpy); - - status_t linkToComposerDeath(const sp<IBinder::DeathRecipient>& recipient, - void* cookie = NULL, uint32_t flags = 0); - status_t hide(SurfaceID id); status_t show(SurfaceID id, int32_t layer = -1); - status_t freeze(SurfaceID id); - status_t unfreeze(SurfaceID id); status_t setFlags(SurfaceID id, uint32_t flags, uint32_t mask); status_t setTransparentRegionHint(SurfaceID id, const Region& transparent); status_t setLayer(SurfaceID id, int32_t layer); status_t setAlpha(SurfaceID id, float alpha=1.0f); - status_t setFreezeTint(SurfaceID id, uint32_t tint); status_t setMatrix(SurfaceID id, float dsdx, float dtdx, float dsdy, float dtdy); status_t setPosition(SurfaceID id, float x, float y); status_t setSize(SurfaceID id, uint32_t w, uint32_t h); status_t setCrop(SurfaceID id, const Rect& crop); + status_t setLayerStack(SurfaceID id, uint32_t layerStack); status_t destroySurface(SurfaceID sid); + static void setDisplaySurface(const sp<IBinder>& token, + const sp<ISurfaceTexture>& surface); + static void setDisplayLayerStack(const sp<IBinder>& token, + uint32_t layerStack); + static void setDisplayOrientation(const sp<IBinder>& token, + uint32_t orientation); + static void setDisplayViewport(const sp<IBinder>& token, + const Rect& viewport); + static void setDisplayFrame(const sp<IBinder>& token, const Rect& frame); + private: virtual void onFirstRef(); Composer& getComposer(); diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h index 2635e2f..0a83ce6 100644 --- a/include/gui/SurfaceTexture.h +++ b/include/gui/SurfaceTexture.h @@ -24,6 +24,7 @@ #include <gui/ISurfaceTexture.h> #include <gui/BufferQueue.h> +#include <gui/ConsumerBase.h> #include <ui/GraphicBuffer.h> @@ -39,20 +40,9 @@ namespace android { class String8; -class SurfaceTexture : public virtual RefBase, - protected BufferQueue::ConsumerListener { +class SurfaceTexture : public ConsumerBase { public: - struct FrameAvailableListener : public virtual RefBase { - // onFrameAvailable() is called each time an additional frame becomes - // available for consumption. This means that frames that are queued - // while in asynchronous mode only trigger the callback if no previous - // frames are pending. Frames queued while in synchronous mode always - // trigger the callback. - // - // This is called without any lock held and can be called concurrently - // by multiple threads. - virtual void onFrameAvailable() = 0; - }; + typedef ConsumerBase::FrameAvailableListener FrameAvailableListener; // SurfaceTexture constructs a new SurfaceTexture object. tex indicates the // name of the OpenGL ES texture to which images are to be streamed. @@ -82,8 +72,6 @@ public: GLenum texTarget = GL_TEXTURE_EXTERNAL_OES, bool useFenceSync = true, const sp<BufferQueue> &bufferQueue = 0); - virtual ~SurfaceTexture(); - // updateTexImage sets the image contents of the target texture to that of // the most recently queued buffer. // @@ -91,6 +79,14 @@ public: // target texture belongs is bound to the calling thread. status_t updateTexImage(); + // setReleaseFence stores a fence file descriptor that will signal when the + // current buffer is no longer being read. This fence will be returned to + // the producer when the current buffer is released by updateTexImage(). + // Multiple fences can be set for a given buffer; they will be merged into + // a single union fence. The SurfaceTexture will close the file descriptor + // when finished with it. + void setReleaseFence(int fenceFd); + // setBufferCountServer set the buffer count. If the client has requested // a buffer count using setBufferCount, the server-buffer count will // take effect once the client sets the count back to zero. @@ -124,16 +120,6 @@ public: // documented by the source. int64_t getTimestamp(); - // setFrameAvailableListener sets the listener object that will be notified - // when a new frame becomes available. - void setFrameAvailableListener(const sp<FrameAvailableListener>& listener); - - // getAllocator retrieves the binder object that must be referenced as long - // as the GraphicBuffers dequeued from this SurfaceTexture are referenced. - // Holding this binder reference prevents SurfaceFlinger from freeing the - // buffers before the client is done with them. - sp<IBinder> getAllocator(); - // setDefaultBufferSize is used to set the size of buffers returned by // requestBuffers when a with and height of zero is requested. // A call to setDefaultBufferSize() may trigger requestBuffers() to @@ -164,21 +150,14 @@ public: // getCurrentScalingMode returns the scaling mode of the current buffer. uint32_t getCurrentScalingMode() const; + // getCurrentFence returns the fence indicating when the current buffer is + // ready to be read from. + sp<Fence> getCurrentFence() const; + // isSynchronousMode returns whether the SurfaceTexture is currently in // synchronous mode. bool isSynchronousMode() const; - // abandon frees all the buffers and puts the SurfaceTexture into the - // 'abandoned' state. Once put in this state the SurfaceTexture can never - // leave it. When in the 'abandoned' state, all methods of the - // ISurfaceTexture interface will fail with the NO_INIT error. - // - // Note that while calling this method causes all the buffers to be freed - // from the perspective of the the SurfaceTexture, if there are additional - // references on the buffers (e.g. if a buffer is referenced by a client or - // by OpenGL ES as a texture) then those buffer will remain allocated. - void abandon(); - // set the name of the SurfaceTexture that will be used to identify it in // log messages. void setName(const String8& name); @@ -192,7 +171,9 @@ public: // getBufferQueue returns the BufferQueue object to which this // SurfaceTexture is connected. - sp<BufferQueue> getBufferQueue() const; + sp<BufferQueue> getBufferQueue() const { + return mBufferQueue; + } // detachFromContext detaches the SurfaceTexture from the calling thread's // current OpenGL ES context. This context must be the same as the context @@ -221,17 +202,25 @@ public: // current at the time of the last call to detachFromContext. status_t attachToContext(GLuint tex); - // dump our state in a String - virtual void dump(String8& result) const; - virtual void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const; - protected: - // Implementation of the BufferQueue::ConsumerListener interface. These - // calls are used to notify the SurfaceTexture of asynchronous events in the - // BufferQueue. - virtual void onFrameAvailable(); - virtual void onBuffersReleased(); + // abandonLocked overrides the ConsumerBase method to clear + // mCurrentTextureBuf in addition to the ConsumerBase behavior. + virtual void abandonLocked(); + + // dumpLocked overrides the ConsumerBase method to dump SurfaceTexture- + // specific info in addition to the ConsumerBase behavior. + virtual void dumpLocked(String8& result, const char* prefix, char* buffer, + size_t size) const; + + // acquireBufferLocked overrides the ConsumerBase method to update the + // mEglSlots array in addition to the ConsumerBase behavior. + virtual status_t acquireBufferLocked(BufferQueue::BufferItem *item); + + // releaseBufferLocked overrides the ConsumerBase method to update the + // mEglSlots array in addition to the ConsumerBase. + virtual status_t releaseBufferLocked(int buf, EGLDisplay display, + EGLSyncKHR eglFence, const sp<Fence>& fence); static bool isExternalFormat(uint32_t format); @@ -295,6 +284,9 @@ private: // set to each time updateTexImage is called. uint32_t mCurrentScalingMode; + // mCurrentFence is the fence received from BufferQueue in updateTexImage. + sp<Fence> mCurrentFence; + // mCurrentTransformMatrix is the transform matrix for the current texture. // It gets computed by computeTransformMatrix each time updateTexImage is // called. @@ -336,11 +328,9 @@ private: struct EGLSlot { EGLSlot() : mEglImage(EGL_NO_IMAGE_KHR), - mFence(EGL_NO_SYNC_KHR) { + mEglFence(EGL_NO_SYNC_KHR) { } - sp<GraphicBuffer> mGraphicBuffer; - // mEglImage is the EGLImage created from mGraphicBuffer. EGLImageKHR mEglImage; @@ -348,7 +338,7 @@ private: // associated with this buffer slot may be dequeued. It is initialized // to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based // on a compile-time option) set to a new sync object in updateTexImage. - EGLSyncKHR mFence; + EGLSyncKHR mEglFence; }; // mEglDisplay is the EGLDisplay with which this SurfaceTexture is currently @@ -370,23 +360,7 @@ private: // slot that has not yet been used. The buffer allocated to a slot will also // be replaced if the requested buffer usage or geometry differs from that // of the buffer allocated to a slot. - EGLSlot mEGLSlots[BufferQueue::NUM_BUFFER_SLOTS]; - - // mAbandoned indicates that the BufferQueue will no longer be used to - // consume images buffers pushed to it using the ISurfaceTexture interface. - // It is initialized to false, and set to true in the abandon method. A - // BufferQueue that has been abandoned will return the NO_INIT error from - // all ISurfaceTexture methods capable of returning an error. - bool mAbandoned; - - // mName is a string used to identify the SurfaceTexture in log messages. - // It can be set by the setName method. - String8 mName; - - // mFrameAvailableListener is the listener object that will be called when a - // new frame becomes available. If it is not NULL it will be called from - // queueBuffer. - sp<FrameAvailableListener> mFrameAvailableListener; + EGLSlot mEglSlots[BufferQueue::NUM_BUFFER_SLOTS]; // mCurrentTexture is the buffer slot index of the buffer that is currently // bound to the OpenGL texture. It is initialized to INVALID_BUFFER_SLOT, @@ -396,22 +370,13 @@ private: // reset mCurrentTexture to INVALID_BUFFER_SLOT. int mCurrentTexture; - // The SurfaceTexture has-a BufferQueue and is responsible for creating this object - // if none is supplied - sp<BufferQueue> mBufferQueue; - - // mAttached indicates whether the SurfaceTexture is currently attached to + // mAttached indicates whether the ConsumerBase is currently attached to // an OpenGL ES context. For legacy reasons, this is initialized to true, - // indicating that the SurfaceTexture is considered to be attached to + // indicating that the ConsumerBase is considered to be attached to // whatever context is current at the time of the first updateTexImage call. // It is set to false by detachFromContext, and then set to true again by // attachToContext. bool mAttached; - - // mMutex is the mutex used to prevent concurrent access to the member - // variables of SurfaceTexture objects. It must be locked whenever the - // member variables are accessed. - mutable Mutex mMutex; }; // ---------------------------------------------------------------------------- diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h index 8fa85b6..50fd1ba 100644 --- a/include/gui/SurfaceTextureClient.h +++ b/include/gui/SurfaceTextureClient.h @@ -61,14 +61,25 @@ private: void init(); // ANativeWindow hooks - static int hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer); - static int hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer); - static int hook_lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer); + static int hook_cancelBuffer(ANativeWindow* window, + ANativeWindowBuffer* buffer, int fenceFd); + static int hook_dequeueBuffer(ANativeWindow* window, + ANativeWindowBuffer** buffer, int* fenceFd); static int hook_perform(ANativeWindow* window, int operation, ...); static int hook_query(const ANativeWindow* window, int what, int* value); - static int hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer); + static int hook_queueBuffer(ANativeWindow* window, + ANativeWindowBuffer* buffer, int fenceFd); static int hook_setSwapInterval(ANativeWindow* window, int interval); + static int hook_cancelBuffer_DEPRECATED(ANativeWindow* window, + ANativeWindowBuffer* buffer); + static int hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, + ANativeWindowBuffer** buffer); + static int hook_lockBuffer_DEPRECATED(ANativeWindow* window, + ANativeWindowBuffer* buffer); + static int hook_queueBuffer_DEPRECATED(ANativeWindow* window, + ANativeWindowBuffer* buffer); + int dispatchConnect(va_list args); int dispatchDisconnect(va_list args); int dispatchSetBufferCount(va_list args); @@ -86,14 +97,15 @@ private: int dispatchUnlockAndPost(va_list args); protected: - virtual int cancelBuffer(ANativeWindowBuffer* buffer); - virtual int dequeueBuffer(ANativeWindowBuffer** buffer); - virtual int lockBuffer(ANativeWindowBuffer* buffer); + virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd); + virtual int cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd); + virtual int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd); virtual int perform(int operation, va_list args); virtual int query(int what, int* value) const; - virtual int queueBuffer(ANativeWindowBuffer* buffer); virtual int setSwapInterval(int interval); + virtual int lockBuffer_DEPRECATED(ANativeWindowBuffer* buffer); + virtual int connect(int api); virtual int disconnect(int api); virtual int setBufferCount(int bufferCount); diff --git a/include/media/openmax/OMX_IVCommon.h b/include/media/openmax/OMX_IVCommon.h index 8bb4ded..effbaae 100644 --- a/include/media/openmax/OMX_IVCommon.h +++ b/include/media/openmax/OMX_IVCommon.h @@ -159,6 +159,7 @@ typedef enum OMX_COLOR_FORMATTYPE { OMX_COLOR_FormatAndroidOpaque = 0x7F000789, OMX_TI_COLOR_FormatYUV420PackedSemiPlanar = 0x7F000100, OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00, + OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka = 0x7FA30C03, OMX_COLOR_FormatMax = 0x7FFFFFFF } OMX_COLOR_FORMATTYPE; diff --git a/include/private/gui/ComposerService.h b/include/private/gui/ComposerService.h index d04491a..c2761b8 100644 --- a/include/private/gui/ComposerService.h +++ b/include/private/gui/ComposerService.h @@ -30,7 +30,6 @@ namespace android { class IMemoryHeap; class ISurfaceComposer; -class surface_flinger_cblk_t; // --------------------------------------------------------------------------- @@ -38,13 +37,10 @@ class ComposerService : public Singleton<ComposerService> { // these are constants sp<ISurfaceComposer> mComposerService; - sp<IMemoryHeap> mServerCblkMemory; - surface_flinger_cblk_t volatile* mServerCblk; ComposerService(); friend class Singleton<ComposerService>; public: static sp<ISurfaceComposer> getComposerService(); - static surface_flinger_cblk_t const volatile * getControlBlock(); }; // --------------------------------------------------------------------------- diff --git a/include/private/gui/LayerState.h b/include/private/gui/LayerState.h index 9151c11..65d9eb3 100644 --- a/include/private/gui/LayerState.h +++ b/include/private/gui/LayerState.h @@ -33,10 +33,27 @@ class ISurfaceComposerClient; struct layer_state_t { + + enum { + eLayerHidden = 0x01, + }; + + enum { + ePositionChanged = 0x00000001, + eLayerChanged = 0x00000002, + eSizeChanged = 0x00000004, + eAlphaChanged = 0x00000008, + eMatrixChanged = 0x00000010, + eTransparentRegionChanged = 0x00000020, + eVisibilityChanged = 0x00000040, + eLayerStackChanged = 0x00000080, + eCropChanged = 0x00000100, + }; + layer_state_t() : surface(0), what(0), - x(0), y(0), z(0), w(0), h(0), - alpha(0), tint(0), flags(0), mask(0), + x(0), y(0), z(0), w(0), h(0), layerStack(0), + alpha(0), flags(0), mask(0), reserved(0) { matrix.dsdx = matrix.dtdy = 1.0f; @@ -60,8 +77,8 @@ struct layer_state_t { uint32_t z; uint32_t w; uint32_t h; + uint32_t layerStack; float alpha; - uint32_t tint; uint8_t flags; uint8_t mask; uint8_t reserved; @@ -78,6 +95,36 @@ struct ComposerState { status_t read(const Parcel& input); }; +struct DisplayState { + + enum { + eOrientationDefault = 0, + eOrientation90 = 1, + eOrientation180 = 2, + eOrientation270 = 3, + eOrientationUnchanged = 4, + eOrientationSwapMask = 0x01 + }; + + enum { + eSurfaceChanged = 0x01, + eLayerStackChanged = 0x02, + eOrientationChanged = 0x04, + eViewportChanged = 0x08, + eFrameChanged = 0x10 + }; + + uint32_t what; + sp<IBinder> token; + sp<ISurfaceTexture> surface; + uint32_t layerStack; + uint32_t orientation; + Rect viewport; + Rect frame; + status_t write(Parcel& output) const; + status_t read(const Parcel& input); +}; + }; // namespace android #endif // ANDROID_SF_LAYER_STATE_H diff --git a/include/ui/DisplayInfo.h b/include/ui/DisplayInfo.h index edd28a6..c7dc354 100644 --- a/include/ui/DisplayInfo.h +++ b/include/ui/DisplayInfo.h @@ -14,7 +14,6 @@ * limitations under the License. */ - #ifndef ANDROID_UI_DISPLAY_INFO_H #define ANDROID_UI_DISPLAY_INFO_H @@ -26,15 +25,16 @@ namespace android { struct DisplayInfo { - uint32_t w; - uint32_t h; - PixelFormatInfo pixelFormatInfo; - uint8_t orientation; - uint8_t reserved[3]; - float fps; - float density; - float xdpi; - float ydpi; + uint32_t w; + uint32_t h; + float xdpi; + float ydpi; + float fps; + float density; + uint8_t orientation; + uint8_t reserved[3]; + // TODO: this needs to go away (currently needed only by webkit) + PixelFormatInfo pixelFormatInfo; }; /* Display orientations as defined in Surface.java and ISurfaceComposer.h. */ @@ -45,8 +45,6 @@ enum { DISPLAY_ORIENTATION_270 = 3 }; - }; // namespace android #endif // ANDROID_COMPOSER_DISPLAY_INFO_H - diff --git a/include/ui/Fence.h b/include/ui/Fence.h new file mode 100644 index 0000000..17cb018 --- /dev/null +++ b/include/ui/Fence.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_FENCE_H +#define ANDROID_FENCE_H + +#include <stdint.h> +#include <limits.h> +#include <sys/types.h> + +#include <ui/ANativeObjectBase.h> +#include <ui/PixelFormat.h> +#include <ui/Rect.h> +#include <utils/Flattenable.h> +#include <utils/String8.h> + +struct ANativeWindowBuffer; + +namespace android { + +// =========================================================================== +// Fence +// =========================================================================== + +class Fence + : public LightRefBase<Fence>, public Flattenable +{ +public: + static const sp<Fence> NO_FENCE; + + // Construct a new Fence object with an invalid file descriptor. This + // should be done when the Fence object will be set up by unflattening + // serialized data. + Fence(); + + // Construct a new Fence object to manage a given fence file descriptor. + // When the new Fence object is destructed the file descriptor will be + // closed. + Fence(int fenceFd); + + // Check whether the Fence has an open fence file descriptor. Most Fence + // methods treat an invalid file descriptor just like a valid fence that + // is already signalled, so using this is usually not necessary. + bool isValid() const { return mFenceFd != -1; } + + // wait waits for up to timeout milliseconds for the fence to signal. If + // the fence signals then NO_ERROR is returned. If the timeout expires + // before the fence signals then -ETIME is returned. A timeout of + // TIMEOUT_NEVER may be used to indicate that the call should wait + // indefinitely for the fence to signal. + int wait(unsigned int timeout); + + // TIMEOUT_NEVER may be passed to the wait method to indicate that it + // should wait indefinitely for the fence to signal. + enum { TIMEOUT_NEVER = UINT_MAX }; + + // merge combines two Fence objects, creating a new Fence object that + // becomes signaled when both f1 and f2 are signaled (even if f1 or f2 is + // destroyed before it becomes signaled). The name argument specifies the + // human-readable name to associated with the new Fence object. + static sp<Fence> merge(const String8& name, const sp<Fence>& f1, + const sp<Fence>& f2); + + // Return a duplicate of the fence file descriptor. The caller is + // responsible for closing the returned file descriptor. On error, -1 will + // be returned and errno will indicate the problem. + int dup() const; + + // Flattenable interface + size_t getFlattenedSize() const; + size_t getFdCount() const; + status_t flatten(void* buffer, size_t size, + int fds[], size_t count) const; + status_t unflatten(void const* buffer, size_t size, + int fds[], size_t count); + +private: + // Only allow instantiation using ref counting. + friend class LightRefBase<Fence>; + virtual ~Fence(); + + // Disallow copying + Fence(const Fence& rhs); + Fence& operator = (const Fence& rhs); + const Fence& operator = (const Fence& rhs) const; + + int mFenceFd; +}; + +}; // namespace android + +#endif // ANDROID_FENCE_H diff --git a/include/ui/FramebufferNativeWindow.h b/include/ui/FramebufferNativeWindow.h index b202b95..5ec738f 100644 --- a/include/ui/FramebufferNativeWindow.h +++ b/include/ui/FramebufferNativeWindow.h @@ -28,7 +28,8 @@ #include <ui/ANativeObjectBase.h> #include <ui/Rect.h> -#define NUM_FRAME_BUFFERS 2 +#define MIN_NUM_FRAME_BUFFERS 2 +#define MAX_NUM_FRAME_BUFFERS 3 extern "C" EGLNativeWindowType android_createDisplaySurface(void); @@ -65,16 +66,19 @@ private: friend class LightRefBase<FramebufferNativeWindow>; ~FramebufferNativeWindow(); // this class cannot be overloaded static int setSwapInterval(ANativeWindow* window, int interval); - static int dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer); - static int lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer); - static int queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer); + static int dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer, int* fenceFd); + static int queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd); static int query(const ANativeWindow* window, int what, int* value); static int perform(ANativeWindow* window, int operation, ...); - + + static int dequeueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer** buffer); + static int queueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer); + static int lockBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer); + framebuffer_device_t* fbDev; alloc_device_t* grDev; - sp<NativeBuffer> buffers[NUM_FRAME_BUFFERS]; + sp<NativeBuffer> buffers[MAX_NUM_FRAME_BUFFERS]; sp<NativeBuffer> front; mutable Mutex mutex; diff --git a/include/ui/Point.h b/include/ui/Point.h index 1653120..1d7f64d 100644 --- a/include/ui/Point.h +++ b/include/ui/Point.h @@ -17,11 +17,12 @@ #ifndef ANDROID_UI_POINT #define ANDROID_UI_POINT +#include <utils/Flattenable.h> #include <utils/TypeHelpers.h> namespace android { -class Point +class Point : public LightFlattenablePod<Point> { public: int x; diff --git a/include/ui/Rect.h b/include/ui/Rect.h index c2c2675..47d37b6 100644 --- a/include/ui/Rect.h +++ b/include/ui/Rect.h @@ -17,6 +17,7 @@ #ifndef ANDROID_UI_RECT #define ANDROID_UI_RECT +#include <utils/Flattenable.h> #include <utils/TypeHelpers.h> #include <ui/Point.h> @@ -24,7 +25,7 @@ namespace android { -class Rect : public ARect +class Rect : public ARect, public LightFlattenablePod<Rect> { public: typedef ARect::value_type value_type; diff --git a/include/ui/Region.h b/include/ui/Region.h index f242f18..f0819af 100644 --- a/include/ui/Region.h +++ b/include/ui/Region.h @@ -23,6 +23,7 @@ #include <utils/Vector.h> #include <ui/Rect.h> +#include <utils/Flattenable.h> namespace android { // --------------------------------------------------------------------------- @@ -30,13 +31,12 @@ namespace android { class String8; // --------------------------------------------------------------------------- -class Region +class Region : public LightFlattenable<Region> { public: Region(); Region(const Region& rhs); explicit Region(const Rect& rhs); - explicit Region(const void* buffer); ~Region(); Region& operator = (const Region& rhs); @@ -122,12 +122,10 @@ public: // be sorted in Y and X and must not make the region invalid. void addRectUnchecked(int l, int t, int r, int b); - // flatten/unflatten a region to/from a raw buffer - ssize_t write(void* buffer, size_t size) const; - static ssize_t writeEmpty(void* buffer, size_t size); - - ssize_t read(const void* buffer); - static bool isEmpty(void* buffer); + inline bool isFixedSize() const { return false; } + size_t getSize() const; + status_t flatten(void* buffer) const; + status_t unflatten(void const* buffer, size_t size); void dump(String8& out, const char* what, uint32_t flags=0) const; void dump(const char* what, uint32_t flags=0) const; diff --git a/include/utils/Flattenable.h b/include/utils/Flattenable.h index 852be3b..e40d289 100644 --- a/include/utils/Flattenable.h +++ b/include/utils/Flattenable.h @@ -24,6 +24,11 @@ namespace android { +/* + * The Flattenable interface allows an object to serialize itself out + * to a byte-buffer and an array of file descriptors. + */ + class Flattenable { public: @@ -56,6 +61,73 @@ protected: }; +/* + * LightFlattenable is a protocol allowing object to serialize themselves out + * to a byte-buffer. + * + * LightFlattenable objects must implement this protocol. + * + * LightFlattenable doesn't require the object to be virtual. + */ +template <typename T> +class LightFlattenable { +public: + // returns whether this object always flatten into the same size. + // for efficiency, this should always be inline. + inline bool isFixedSize() const; + + // returns size in bytes of the flattened object. must be a constant. + inline size_t getSize() const; + + // flattens the object into buffer. + inline status_t flatten(void* buffer) const; + + // unflattens the object from buffer of given size. + inline status_t unflatten(void const* buffer, size_t size); +}; + +template <typename T> +inline bool LightFlattenable<T>::isFixedSize() const { + return static_cast<T const*>(this)->T::isFixedSize(); +} +template <typename T> +inline size_t LightFlattenable<T>::getSize() const { + return static_cast<T const*>(this)->T::getSize(); +} +template <typename T> +inline status_t LightFlattenable<T>::flatten(void* buffer) const { + return static_cast<T const*>(this)->T::flatten(buffer); +} +template <typename T> +inline status_t LightFlattenable<T>::unflatten(void const* buffer, size_t size) { + return static_cast<T*>(this)->T::unflatten(buffer, size); +} + +/* + * LightFlattenablePod is an implementation of the LightFlattenable protocol + * for POD (plain-old-data) objects. + */ +template <typename T> +class LightFlattenablePod : public LightFlattenable<T> { +public: + inline bool isFixedSize() const { + return true; + } + + inline size_t getSize() const { + return sizeof(T); + } + inline status_t flatten(void* buffer) const { + *reinterpret_cast<T*>(buffer) = *static_cast<T const*>(this); + return NO_ERROR; + } + inline status_t unflatten(void const* buffer, size_t) { + *static_cast<T*>(this) = *reinterpret_cast<T const*>(buffer); + return NO_ERROR; + } +}; + + }; // namespace android diff --git a/include/utils/KeyedVector.h b/include/utils/KeyedVector.h index 20575ee..c4faae0 100644 --- a/include/utils/KeyedVector.h +++ b/include/utils/KeyedVector.h @@ -21,6 +21,8 @@ #include <stdint.h> #include <sys/types.h> +#include <cutils/log.h> + #include <utils/SortedVector.h> #include <utils/TypeHelpers.h> #include <utils/Errors.h> @@ -50,13 +52,16 @@ public: //! returns number of items in the vector inline size_t size() const { return mVector.size(); } - //! returns wether or not the vector is empty + //! returns whether or not the vector is empty inline bool isEmpty() const { return mVector.isEmpty(); } //! returns how many items can be stored without reallocating the backing store inline size_t capacity() const { return mVector.capacity(); } - //! setst the capacity. capacity can never be reduced less than size() + //! sets the capacity. capacity can never be reduced less than size() inline ssize_t setCapacity(size_t size) { return mVector.setCapacity(size); } - + + // returns true if the arguments is known to be identical to this vector + inline bool isIdenticalTo(const KeyedVector& rhs) const; + /*! * accessors */ @@ -64,6 +69,7 @@ public: const VALUE& valueAt(size_t index) const; const KEY& keyAt(size_t index) const; ssize_t indexOfKey(const KEY& key) const; + const VALUE& operator[] (size_t index) const; /*! * modifying the array @@ -123,6 +129,11 @@ KeyedVector<KEY,VALUE>::KeyedVector() } template<typename KEY, typename VALUE> inline +bool KeyedVector<KEY,VALUE>::isIdenticalTo(const KeyedVector<KEY,VALUE>& rhs) const { + return mVector.array() == rhs.mVector.array(); +} + +template<typename KEY, typename VALUE> inline ssize_t KeyedVector<KEY,VALUE>::indexOfKey(const KEY& key) const { return mVector.indexOf( key_value_pair_t<KEY,VALUE>(key) ); } @@ -130,7 +141,7 @@ ssize_t KeyedVector<KEY,VALUE>::indexOfKey(const KEY& key) const { template<typename KEY, typename VALUE> inline const VALUE& KeyedVector<KEY,VALUE>::valueFor(const KEY& key) const { ssize_t i = this->indexOfKey(key); - assert(i>=0); + LOG_ALWAYS_FATAL_IF(i<0, "%s: key not found", __PRETTY_FUNCTION__); return mVector.itemAt(i).value; } @@ -140,6 +151,11 @@ const VALUE& KeyedVector<KEY,VALUE>::valueAt(size_t index) const { } template<typename KEY, typename VALUE> inline +const VALUE& KeyedVector<KEY,VALUE>::operator[] (size_t index) const { + return valueAt(index); +} + +template<typename KEY, typename VALUE> inline const KEY& KeyedVector<KEY,VALUE>::keyAt(size_t index) const { return mVector.itemAt(index).key; } @@ -147,7 +163,7 @@ const KEY& KeyedVector<KEY,VALUE>::keyAt(size_t index) const { template<typename KEY, typename VALUE> inline VALUE& KeyedVector<KEY,VALUE>::editValueFor(const KEY& key) { ssize_t i = this->indexOfKey(key); - assert(i>=0); + LOG_ALWAYS_FATAL_IF(i<0, "%s: key not found", __PRETTY_FUNCTION__); return mVector.editItemAt(i).value; } diff --git a/include/utils/Log.h b/include/utils/Log.h index 3c6cc8b..98c441c 100644 --- a/include/utils/Log.h +++ b/include/utils/Log.h @@ -29,5 +29,43 @@ #define _LIBS_UTILS_LOG_H #include <cutils/log.h> +#include <sys/types.h> + +#ifdef __cplusplus + +namespace android { + +/* + * A very simple utility that yells in the log when an operation takes too long. + */ +class LogIfSlow { +public: + LogIfSlow(const char* tag, android_LogPriority priority, + int timeoutMillis, const char* message); + ~LogIfSlow(); + +private: + const char* const mTag; + const android_LogPriority mPriority; + const int mTimeoutMillis; + const char* const mMessage; + const int64_t mStart; +}; + +/* + * Writes the specified debug log message if this block takes longer than the + * specified number of milliseconds to run. Includes the time actually taken. + * + * { + * ALOGD_IF_SLOW(50, "Excessive delay doing something."); + * doSomething(); + * } + */ +#define ALOGD_IF_SLOW(timeoutMillis, message) \ + LogIfSlow _logIfSlow(LOG_TAG, ANDROID_LOG_DEBUG, timeoutMillis, message); + +} // namespace android + +#endif // __cplusplus #endif // _LIBS_UTILS_LOG_H diff --git a/include/utils/SortedVector.h b/include/utils/SortedVector.h index 2445525..fd1cb82 100644 --- a/include/utils/SortedVector.h +++ b/include/utils/SortedVector.h @@ -21,6 +21,8 @@ #include <stdint.h> #include <sys/types.h> +#include <cutils/log.h> + #include <utils/Vector.h> #include <utils/VectorImpl.h> #include <utils/TypeHelpers.h> @@ -61,11 +63,11 @@ public: //! returns number of items in the vector inline size_t size() const { return VectorImpl::size(); } - //! returns wether or not the vector is empty + //! returns whether or not the vector is empty inline bool isEmpty() const { return VectorImpl::isEmpty(); } //! returns how many items can be stored without reallocating the backing store inline size_t capacity() const { return VectorImpl::capacity(); } - //! setst the capacity. capacity can never be reduced less than size() + //! sets the capacity. capacity can never be reduced less than size() inline ssize_t setCapacity(size_t size) { return VectorImpl::setCapacity(size); } /*! @@ -76,7 +78,7 @@ public: inline const TYPE* array() const; //! read-write C-style access. BE VERY CAREFUL when modifying the array - //! you ust keep it sorted! You usually don't use this function. + //! you must keep it sorted! You usually don't use this function. TYPE* editArray(); //! finds the index of an item @@ -100,7 +102,7 @@ public: const TYPE& mirrorItemAt(ssize_t index) const; /*! - * modifing the array + * modifying the array */ //! add an item in the right place (and replace the one that is there) @@ -186,7 +188,9 @@ TYPE* SortedVector<TYPE>::editArray() { template<class TYPE> inline const TYPE& SortedVector<TYPE>::operator[](size_t index) const { - assert( index<size() ); + LOG_FATAL_IF(index>=size(), + "%s: index=%u out of range (%u)", __PRETTY_FUNCTION__, + int(index), int(size())); return *(array() + index); } @@ -197,8 +201,11 @@ const TYPE& SortedVector<TYPE>::itemAt(size_t index) const { template<class TYPE> inline const TYPE& SortedVector<TYPE>::mirrorItemAt(ssize_t index) const { - assert( (index>0 ? index : -index)<size() ); - return *(array() + ((index<0) ? (size()-index) : index)); + const size_t i = index>0 ? index : -index; + LOG_FATAL_IF(index>=size(), + "%s: index=%u out of range (%u)", __PRETTY_FUNCTION__, + int(index), int(size())); + return *(array() + i); } template<class TYPE> inline diff --git a/include/utils/SystemClock.h b/include/utils/SystemClock.h index 7c319be..d75264c 100644 --- a/include/utils/SystemClock.h +++ b/include/utils/SystemClock.h @@ -25,6 +25,7 @@ namespace android { int setCurrentTimeMillis(int64_t millis); int64_t uptimeMillis(); int64_t elapsedRealtime(); +int64_t elapsedRealtimeNano(); }; // namespace android diff --git a/include/utils/Timers.h b/include/utils/Timers.h index 8b4d322..92f66c9 100644 --- a/include/utils/Timers.h +++ b/include/utils/Timers.h @@ -78,9 +78,10 @@ enum { SYSTEM_TIME_REALTIME = 0, // system-wide realtime clock SYSTEM_TIME_MONOTONIC = 1, // monotonic time since unspecified starting point SYSTEM_TIME_PROCESS = 2, // high-resolution per-process clock - SYSTEM_TIME_THREAD = 3 // high-resolution per-thread clock + SYSTEM_TIME_THREAD = 3, // high-resolution per-thread clock + SYSTEM_TIME_BOOTTIME = 4 // same as SYSTEM_TIME_MONOTONIC, but including CPU suspend time }; - + // return the system-time according to the specified clock #ifdef __cplusplus nsecs_t systemTime(int clock = SYSTEM_TIME_MONOTONIC); diff --git a/include/utils/Trace.h b/include/utils/Trace.h index 4219206..e5cc7ec 100644 --- a/include/utils/Trace.h +++ b/include/utils/Trace.h @@ -51,7 +51,8 @@ #define ATRACE_TAG_SYNC_MANAGER (1<<7) #define ATRACE_TAG_AUDIO (1<<8) #define ATRACE_TAG_VIDEO (1<<9) -#define ATRACE_TAG_LAST ATRACE_TAG_VIDEO +#define ATRACE_TAG_CAMERA (1<<10) +#define ATRACE_TAG_LAST ATRACE_TAG_CAMERA #define ATRACE_TAG_VALID_MASK ((ATRACE_TAG_LAST - 1) | ATRACE_TAG_LAST) diff --git a/include/utils/Vector.h b/include/utils/Vector.h index e39a5b7..506acae 100644 --- a/include/utils/Vector.h +++ b/include/utils/Vector.h @@ -21,7 +21,8 @@ #include <stdint.h> #include <sys/types.h> -#include <utils/Log.h> +#include <cutils/log.h> + #include <utils/VectorImpl.h> #include <utils/TypeHelpers.h> @@ -72,11 +73,11 @@ public: //! returns number of items in the vector inline size_t size() const { return VectorImpl::size(); } - //! returns wether or not the vector is empty + //! returns whether or not the vector is empty inline bool isEmpty() const { return VectorImpl::isEmpty(); } //! returns how many items can be stored without reallocating the backing store inline size_t capacity() const { return VectorImpl::capacity(); } - //! setst the capacity. capacity can never be reduced less than size() + //! sets the capacity. capacity can never be reduced less than size() inline ssize_t setCapacity(size_t size) { return VectorImpl::setCapacity(size); } /*! @@ -102,12 +103,12 @@ public: const TYPE& mirrorItemAt(ssize_t index) const; /*! - * modifing the array + * modifying the array */ //! copy-on write support, grants write access to an item TYPE& editItemAt(size_t index); - //! grants right acces to the top of the stack (last element) + //! grants right access to the top of the stack (last element) TYPE& editTop(); /*! @@ -271,8 +272,9 @@ TYPE* Vector<TYPE>::editArray() { template<class TYPE> inline const TYPE& Vector<TYPE>::operator[](size_t index) const { - LOG_FATAL_IF( index>=size(), - "itemAt: index %d is past size %d", (int)index, (int)size() ); + LOG_FATAL_IF(index>=size(), + "%s: index=%u out of range (%u)", __PRETTY_FUNCTION__, + int(index), int(size())); return *(array() + index); } @@ -283,10 +285,11 @@ const TYPE& Vector<TYPE>::itemAt(size_t index) const { template<class TYPE> inline const TYPE& Vector<TYPE>::mirrorItemAt(ssize_t index) const { - LOG_FATAL_IF( (index>0 ? index : -index)>=size(), - "mirrorItemAt: index %d is past size %d", - (int)index, (int)size() ); - return *(array() + ((index<0) ? (size()-index) : index)); + const size_t i = index>0 ? index : -index; + LOG_FATAL_IF(index>=size(), + "%s: index=%u out of range (%u)", __PRETTY_FUNCTION__, + int(index), int(size())); + return *(array() + i); } template<class TYPE> inline diff --git a/include/utils/VectorImpl.h b/include/utils/VectorImpl.h index c4ec2ff..b1224c6 100644 --- a/include/utils/VectorImpl.h +++ b/include/utils/VectorImpl.h @@ -104,16 +104,6 @@ protected: virtual void do_splat(void* dest, const void* item, size_t num) const = 0; virtual void do_move_forward(void* dest, const void* from, size_t num) const = 0; virtual void do_move_backward(void* dest, const void* from, size_t num) const = 0; - - // take care of FBC... - virtual void reservedVectorImpl1(); - virtual void reservedVectorImpl2(); - virtual void reservedVectorImpl3(); - virtual void reservedVectorImpl4(); - virtual void reservedVectorImpl5(); - virtual void reservedVectorImpl6(); - virtual void reservedVectorImpl7(); - virtual void reservedVectorImpl8(); private: void* _grow(size_t where, size_t amount); @@ -165,16 +155,6 @@ public: protected: virtual int do_compare(const void* lhs, const void* rhs) const = 0; - // take care of FBC... - virtual void reservedSortedVectorImpl1(); - virtual void reservedSortedVectorImpl2(); - virtual void reservedSortedVectorImpl3(); - virtual void reservedSortedVectorImpl4(); - virtual void reservedSortedVectorImpl5(); - virtual void reservedSortedVectorImpl6(); - virtual void reservedSortedVectorImpl7(); - virtual void reservedSortedVectorImpl8(); - private: ssize_t _indexOrderOf(const void* item, size_t* order = 0) const; diff --git a/include/utils/misc.h b/include/utils/misc.h index d7d5bc1..f1aa432 100644 --- a/include/utils/misc.h +++ b/include/utils/misc.h @@ -23,41 +23,12 @@ #include <sys/time.h> #include <utils/Endian.h> -namespace android { - /* get #of elements in a static array */ #ifndef NELEM # define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0]))) #endif -/* - * Make a copy of the string, using "new[]" instead of "malloc". Free the - * string with delete[]. - * - * Returns NULL if "str" is NULL. - */ -char* strdupNew(const char* str); - -/* - * Concatenate an argument vector into a single string. If argc is >= 0 - * it will be used; if it's < 0 then the last element in the arg vector - * must be NULL. - * - * This inserts a space between each argument. - * - * This does not automatically add double quotes around arguments with - * spaces in them. This practice is necessary for Win32, because Win32's - * CreateProcess call is stupid. - * - * The caller should delete[] the returned string. - */ -char* concatArgv(int argc, const char* const argv[]); - -/* - * Count up the number of arguments in "argv". The count does not include - * the final NULL entry. - */ -int countArgv(const char* const argv[]); +namespace android { /* * Some utility functions for working with files. These could be made @@ -79,15 +50,6 @@ FileType getFileType(const char* fileName); /* get the file's modification date; returns -1 w/errno set on failure */ time_t getFileModDate(const char* fileName); -/* - * Round up to the nearest power of 2. Handy for hash tables. - */ -unsigned int roundUpPower2(unsigned int val); - -void strreverse(char* begin, char* end); -void k_itoa(int value, char* str, int base); -char* itoa(int val, int base); - typedef void (*sysprop_change_callback)(void); void add_sysprop_change_callback(sysprop_change_callback cb, int priority); void report_sysprop_change(); diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk index 8224847..3aa3a50 100644 --- a/libs/gui/Android.mk +++ b/libs/gui/Android.mk @@ -4,6 +4,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ BitTube.cpp \ BufferQueue.cpp \ + ConsumerBase.cpp \ DisplayEventReceiver.cpp \ IDisplayEventConnection.cpp \ ISensorEventConnection.cpp \ @@ -21,17 +22,17 @@ LOCAL_SRC_FILES:= \ LayerState.cpp \ Surface.cpp \ SurfaceComposerClient.cpp \ - DummyConsumer.cpp + DummyConsumer.cpp \ + CpuConsumer.cpp LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libutils \ libbinder \ - libhardware \ - libhardware_legacy \ - libui \ + libcutils \ libEGL \ libGLESv2 \ + libsync \ + libui \ + libutils \ LOCAL_MODULE:= libgui @@ -42,6 +43,9 @@ endif ifeq ($(TARGET_BOARD_PLATFORM), s5pc110) LOCAL_CFLAGS += -DUSE_FENCE_SYNC endif +ifeq ($(TARGET_BOARD_PLATFORM), exynos5) + LOCAL_CFLAGS += -DUSE_FENCE_SYNC +endif ifneq ($(filter generic%,$(TARGET_DEVICE)),) # Emulator build LOCAL_CFLAGS += -DUSE_FENCE_SYNC diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index a0774cf..697635b 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -81,10 +81,10 @@ static const char* scalingModeName(int scalingMode) { } } -BufferQueue::BufferQueue( bool allowSynchronousMode, int bufferCount ) : +BufferQueue::BufferQueue(bool allowSynchronousMode, int bufferCount, + const sp<IGraphicBufferAlloc>& allocator) : mDefaultWidth(1), mDefaultHeight(1), - mPixelFormat(PIXEL_FORMAT_RGBA_8888), mMinUndequeuedBuffers(bufferCount), mMinAsyncBufferSlots(bufferCount + 1), mMinSyncBufferSlots(bufferCount), @@ -97,7 +97,7 @@ BufferQueue::BufferQueue( bool allowSynchronousMode, int bufferCount ) : mAbandoned(false), mFrameCounter(0), mBufferHasBeenQueued(false), - mDefaultBufferFormat(0), + mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888), mConsumerUsageBits(0), mTransformHint(0) { @@ -105,10 +105,14 @@ BufferQueue::BufferQueue( bool allowSynchronousMode, int bufferCount ) : mConsumerName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); ST_LOGV("BufferQueue"); - sp<ISurfaceComposer> composer(ComposerService::getComposerService()); - mGraphicBufferAlloc = composer->createGraphicBufferAlloc(); - if (mGraphicBufferAlloc == 0) { - ST_LOGE("createGraphicBufferAlloc() failed in BufferQueue()"); + if (allocator == NULL) { + sp<ISurfaceComposer> composer(ComposerService::getComposerService()); + mGraphicBufferAlloc = composer->createGraphicBufferAlloc(); + if (mGraphicBufferAlloc == 0) { + ST_LOGE("createGraphicBufferAlloc() failed in BufferQueue()"); + } + } else { + mGraphicBufferAlloc = allocator; } } @@ -120,7 +124,8 @@ status_t BufferQueue::setBufferCountServerLocked(int bufferCount) { if (bufferCount > NUM_BUFFER_SLOTS) return BAD_VALUE; - // special-case, nothing to do + mServerBufferCount = bufferCount; + if (bufferCount == mBufferCount) return OK; @@ -128,7 +133,6 @@ status_t BufferQueue::setBufferCountServerLocked(int bufferCount) { bufferCount >= mBufferCount) { // easy, we just have more buffers mBufferCount = bufferCount; - mServerBufferCount = bufferCount; mDequeueCondition.broadcast(); } else { // we're here because we're either @@ -145,7 +149,6 @@ status_t BufferQueue::setBufferCountServerLocked(int bufferCount) { // own one. the actual resizing will happen during the next // dequeueBuffer. - mServerBufferCount = bufferCount; mDequeueCondition.broadcast(); } return OK; @@ -255,7 +258,7 @@ int BufferQueue::query(int what, int* outValue) value = mDefaultHeight; break; case NATIVE_WINDOW_FORMAT: - value = mPixelFormat; + value = mDefaultBufferFormat; break; case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: value = mSynchronousMode ? @@ -289,8 +292,8 @@ status_t BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) { return NO_ERROR; } -status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, - uint32_t format, uint32_t usage) { +status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence, + uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { ATRACE_CALL(); ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage); @@ -301,7 +304,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, status_t returnFlags(OK); EGLDisplay dpy = EGL_NO_DISPLAY; - EGLSyncKHR fence = EGL_NO_SYNC_KHR; + EGLSyncKHR eglFence = EGL_NO_SYNC_KHR; { // Scope for the lock Mutex::Autolock lock(mMutex); @@ -313,7 +316,6 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, usage |= mConsumerUsageBits; int found = -1; - int foundSync = -1; int dequeuedCount = 0; bool tryAgain = true; while (tryAgain) { @@ -364,7 +366,6 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, // look for a free buffer to give to the client found = INVALID_BUFFER_SLOT; - foundSync = INVALID_BUFFER_SLOT; dequeuedCount = 0; for (int i = 0; i < mBufferCount; i++) { const int state = mSlots[i].mBufferState; @@ -388,7 +389,6 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, bool isOlder = mSlots[i].mFrameNumber < mSlots[found].mFrameNumber; if (found < 0 || isOlder) { - foundSync = i; found = i; } } @@ -445,12 +445,6 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, h = mDefaultHeight; } - const bool updateFormat = (format != 0); - if (!updateFormat) { - // keep the current (or default) format - format = mPixelFormat; - } - // buffer is now in DEQUEUED (but can also be current at the same time, // if we're in synchronous mode) mSlots[buf].mBufferState = BufferSlot::DEQUEUED; @@ -471,26 +465,26 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, "failed"); return error; } - if (updateFormat) { - mPixelFormat = format; - } mSlots[buf].mAcquireCalled = false; mSlots[buf].mGraphicBuffer = graphicBuffer; mSlots[buf].mRequestBufferCalled = false; - mSlots[buf].mFence = EGL_NO_SYNC_KHR; + mSlots[buf].mEglFence = EGL_NO_SYNC_KHR; + mSlots[buf].mFence.clear(); mSlots[buf].mEglDisplay = EGL_NO_DISPLAY; returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION; } dpy = mSlots[buf].mEglDisplay; - fence = mSlots[buf].mFence; - mSlots[buf].mFence = EGL_NO_SYNC_KHR; + eglFence = mSlots[buf].mEglFence; + outFence = mSlots[buf].mFence; + mSlots[buf].mEglFence = EGL_NO_SYNC_KHR; + mSlots[buf].mFence.clear(); } // end lock scope - if (fence != EGL_NO_SYNC_KHR) { - EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000); + if (eglFence != EGL_NO_SYNC_KHR) { + EGLint result = eglClientWaitSyncKHR(dpy, eglFence, 0, 1000000000); // If something goes wrong, log the error, but return the buffer without // synchronizing access to it. It's too late at this point to abort the // dequeue operation. @@ -499,7 +493,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, } else if (result == EGL_TIMEOUT_EXPIRED_KHR) { ST_LOGE("dequeueBuffer: timeout waiting for fence"); } - eglDestroySyncKHR(dpy, fence); + eglDestroySyncKHR(dpy, eglFence); } ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf, @@ -549,8 +543,9 @@ status_t BufferQueue::queueBuffer(int buf, uint32_t transform; int scalingMode; int64_t timestamp; + sp<Fence> fence; - input.deflate(×tamp, &crop, &scalingMode, &transform); + input.deflate(×tamp, &crop, &scalingMode, &transform, &fence); ST_LOGV("queueBuffer: slot=%d time=%#llx crop=[%d,%d,%d,%d] tr=%#x " "scale=%s", @@ -617,6 +612,7 @@ status_t BufferQueue::queueBuffer(int buf, mSlots[buf].mTimestamp = timestamp; mSlots[buf].mCrop = crop; mSlots[buf].mTransform = transform; + mSlots[buf].mFence = fence; switch (scalingMode) { case NATIVE_WINDOW_SCALING_MODE_FREEZE: @@ -650,7 +646,7 @@ status_t BufferQueue::queueBuffer(int buf, return OK; } -void BufferQueue::cancelBuffer(int buf) { +void BufferQueue::cancelBuffer(int buf, sp<Fence> fence) { ATRACE_CALL(); ST_LOGV("cancelBuffer: slot=%d", buf); Mutex::Autolock lock(mMutex); @@ -671,6 +667,7 @@ void BufferQueue::cancelBuffer(int buf) { } mSlots[buf].mBufferState = BufferSlot::FREE; mSlots[buf].mFrameNumber = 0; + mSlots[buf].mFence = fence; mDequeueCondition.broadcast(); } @@ -783,9 +780,9 @@ void BufferQueue::dump(String8& result, const char* prefix, snprintf(buffer, SIZE, "%s-BufferQueue mBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], " - "mPixelFormat=%d, FIFO(%d)={%s}\n", + "default-format=%d, FIFO(%d)={%s}\n", prefix, mBufferCount, mSynchronousMode, mDefaultWidth, - mDefaultHeight, mPixelFormat, fifoSize, fifo.string()); + mDefaultHeight, mDefaultBufferFormat, fifoSize, fifo.string()); result.append(buffer); @@ -827,20 +824,22 @@ void BufferQueue::dump(String8& result, const char* prefix, } } -void BufferQueue::freeBufferLocked(int i) { - mSlots[i].mGraphicBuffer = 0; - if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) { - mSlots[i].mNeedsCleanupOnRelease = true; +void BufferQueue::freeBufferLocked(int slot) { + ST_LOGV("freeBufferLocked: slot=%d", slot); + mSlots[slot].mGraphicBuffer = 0; + if (mSlots[slot].mBufferState == BufferSlot::ACQUIRED) { + mSlots[slot].mNeedsCleanupOnRelease = true; } - mSlots[i].mBufferState = BufferSlot::FREE; - mSlots[i].mFrameNumber = 0; - mSlots[i].mAcquireCalled = false; + mSlots[slot].mBufferState = BufferSlot::FREE; + mSlots[slot].mFrameNumber = 0; + mSlots[slot].mAcquireCalled = false; // destroy fence as BufferQueue now takes ownership - if (mSlots[i].mFence != EGL_NO_SYNC_KHR) { - eglDestroySyncKHR(mSlots[i].mEglDisplay, mSlots[i].mFence); - mSlots[i].mFence = EGL_NO_SYNC_KHR; + if (mSlots[slot].mEglFence != EGL_NO_SYNC_KHR) { + eglDestroySyncKHR(mSlots[slot].mEglDisplay, mSlots[slot].mEglFence); + mSlots[slot].mEglFence = EGL_NO_SYNC_KHR; } + mSlots[slot].mFence.clear(); } void BufferQueue::freeAllBuffersLocked() { @@ -876,9 +875,13 @@ status_t BufferQueue::acquireBuffer(BufferItem *buffer) { buffer->mFrameNumber = mSlots[buf].mFrameNumber; buffer->mTimestamp = mSlots[buf].mTimestamp; buffer->mBuf = buf; - mSlots[buf].mAcquireCalled = true; + buffer->mFence = mSlots[buf].mFence; + mSlots[buf].mAcquireCalled = true; + mSlots[buf].mNeedsCleanupOnRelease = false; mSlots[buf].mBufferState = BufferSlot::ACQUIRED; + mSlots[buf].mFence.clear(); + mQueue.erase(front); mDequeueCondition.broadcast(); @@ -891,7 +894,7 @@ status_t BufferQueue::acquireBuffer(BufferItem *buffer) { } status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display, - EGLSyncKHR fence) { + EGLSyncKHR eglFence, const sp<Fence>& fence) { ATRACE_CALL(); ATRACE_BUFFER_INDEX(buf); @@ -902,6 +905,7 @@ status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display, } mSlots[buf].mEglDisplay = display; + mSlots[buf].mEglFence = eglFence; mSlots[buf].mFence = fence; // The buffer can now only be released if its in the acquired state diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp new file mode 100644 index 0000000..17bbfd1 --- /dev/null +++ b/libs/gui/ConsumerBase.cpp @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2010 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 "ConsumerBase" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS +//#define LOG_NDEBUG 0 + +#define GL_GLEXT_PROTOTYPES +#define EGL_EGLEXT_PROTOTYPES + +#include <EGL/egl.h> +#include <EGL/eglext.h> + +#include <hardware/hardware.h> + +#include <gui/IGraphicBufferAlloc.h> +#include <gui/ISurfaceComposer.h> +#include <gui/SurfaceComposerClient.h> +#include <gui/ConsumerBase.h> + +#include <private/gui/ComposerService.h> + +#include <utils/Log.h> +#include <utils/String8.h> +#include <utils/Trace.h> + +// Macros for including the ConsumerBase name in log messages +#define CB_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__) +#define CB_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__) +#define CB_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__) +#define CB_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__) +#define CB_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__) + +namespace android { + +// Get an ID that's unique within this process. +static int32_t createProcessUniqueId() { + static volatile int32_t globalCounter = 0; + return android_atomic_inc(&globalCounter); +} + +ConsumerBase::ConsumerBase(const sp<BufferQueue>& bufferQueue) : + mAbandoned(false), + mBufferQueue(bufferQueue) { + // Choose a name using the PID and a process-unique ID. + mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); + + // Note that we can't create an sp<...>(this) in a ctor that will not keep a + // reference once the ctor ends, as that would cause the refcount of 'this' + // dropping to 0 at the end of the ctor. Since all we need is a wp<...> + // that's what we create. + wp<BufferQueue::ConsumerListener> listener; + sp<BufferQueue::ConsumerListener> proxy; + listener = static_cast<BufferQueue::ConsumerListener*>(this); + proxy = new BufferQueue::ProxyConsumerListener(listener); + + status_t err = mBufferQueue->consumerConnect(proxy); + if (err != NO_ERROR) { + CB_LOGE("SurfaceTexture: error connecting to BufferQueue: %s (%d)", + strerror(-err), err); + } else { + mBufferQueue->setConsumerName(mName); + } +} + +ConsumerBase::~ConsumerBase() { + CB_LOGV("~ConsumerBase"); + abandon(); +} + +void ConsumerBase::freeBufferLocked(int slotIndex) { + CB_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); + mSlots[slotIndex].mGraphicBuffer = 0; + mSlots[slotIndex].mFence = 0; +} + +// Used for refactoring, should not be in final interface +sp<BufferQueue> ConsumerBase::getBufferQueue() const { + Mutex::Autolock lock(mMutex); + return mBufferQueue; +} + +void ConsumerBase::onFrameAvailable() { + CB_LOGV("onFrameAvailable"); + + sp<FrameAvailableListener> listener; + { // scope for the lock + Mutex::Autolock lock(mMutex); + listener = mFrameAvailableListener; + } + + if (listener != NULL) { + CB_LOGV("actually calling onFrameAvailable"); + listener->onFrameAvailable(); + } +} + +void ConsumerBase::onBuffersReleased() { + Mutex::Autolock lock(mMutex); + + CB_LOGV("onBuffersReleased"); + + if (mAbandoned) { + // Nothing to do if we're already abandoned. + return; + } + + uint32_t mask = 0; + mBufferQueue->getReleasedBuffers(&mask); + for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { + if (mask & (1 << i)) { + freeBufferLocked(i); + } + } +} + +void ConsumerBase::abandon() { + CB_LOGV("abandon"); + Mutex::Autolock lock(mMutex); + + if (!mAbandoned) { + abandonLocked(); + mAbandoned = true; + } +} + +void ConsumerBase::abandonLocked() { + CB_LOGV("abandonLocked"); + for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { + freeBufferLocked(i); + } + // disconnect from the BufferQueue + mBufferQueue->consumerDisconnect(); + mBufferQueue.clear(); +} + +void ConsumerBase::setFrameAvailableListener( + const sp<FrameAvailableListener>& listener) { + CB_LOGV("setFrameAvailableListener"); + Mutex::Autolock lock(mMutex); + mFrameAvailableListener = listener; +} + +void ConsumerBase::dump(String8& result) const { + char buffer[1024]; + dump(result, "", buffer, 1024); +} + +void ConsumerBase::dump(String8& result, const char* prefix, + char* buffer, size_t size) const { + Mutex::Autolock _l(mMutex); + dumpLocked(result, prefix, buffer, size); +} + +void ConsumerBase::dumpLocked(String8& result, const char* prefix, + char* buffer, size_t SIZE) const { + snprintf(buffer, SIZE, "%smAbandoned=%d\n", prefix, int(mAbandoned)); + result.append(buffer); + + if (!mAbandoned) { + mBufferQueue->dump(result, prefix, buffer, SIZE); + } +} + +status_t ConsumerBase::acquireBufferLocked(BufferQueue::BufferItem *item) { + status_t err = mBufferQueue->acquireBuffer(item); + if (err != NO_ERROR) { + return err; + } + + if (item->mGraphicBuffer != NULL) { + mSlots[item->mBuf].mGraphicBuffer = item->mGraphicBuffer; + } + + CB_LOGV("acquireBufferLocked: -> slot=%d", item->mBuf); + + return OK; +} + +status_t ConsumerBase::releaseBufferLocked(int slot, EGLDisplay display, + EGLSyncKHR eglFence, const sp<Fence>& fence) { + CB_LOGV("releaseBufferLocked: slot=%d", slot); + status_t err = mBufferQueue->releaseBuffer(slot, display, eglFence, fence); + if (err == BufferQueue::STALE_BUFFER_SLOT) { + freeBufferLocked(slot); + } + + mSlots[slot].mFence.clear(); + + return err; +} + +} // namespace android
\ No newline at end of file diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp new file mode 100644 index 0000000..513828c --- /dev/null +++ b/libs/gui/CpuConsumer.cpp @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "CpuConsumer" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS +#include <utils/Log.h> + +#include <gui/CpuConsumer.h> + +#define CC_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__) +#define CC_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__) +#define CC_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__) +#define CC_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__) +#define CC_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__) + +namespace android { + +// Get an ID that's unique within this process. +static int32_t createProcessUniqueId() { + static volatile int32_t globalCounter = 0; + return android_atomic_inc(&globalCounter); +} + +CpuConsumer::CpuConsumer(uint32_t maxLockedBuffers) : + mMaxLockedBuffers(maxLockedBuffers), + mCurrentLockedBuffers(0) +{ + mName = String8::format("cc-unnamed-%d-%d", getpid(), + createProcessUniqueId()); + + for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { + mBufferPointers[i] = NULL; + } + + mBufferQueue = new BufferQueue(true); + + wp<BufferQueue::ConsumerListener> listener; + sp<BufferQueue::ConsumerListener> proxy; + listener = static_cast<BufferQueue::ConsumerListener*>(this); + proxy = new BufferQueue::ProxyConsumerListener(listener); + + status_t err = mBufferQueue->consumerConnect(proxy); + if (err != NO_ERROR) { + ALOGE("CpuConsumer: error connecting to BufferQueue: %s (%d)", + strerror(-err), err); + } else { + mBufferQueue->setSynchronousMode(true); + mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_SW_READ_OFTEN); + mBufferQueue->setConsumerName(mName); + } +} + +CpuConsumer::~CpuConsumer() +{ + Mutex::Autolock _l(mMutex); + for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { + freeBufferLocked(i); + } + mBufferQueue->consumerDisconnect(); + mBufferQueue.clear(); +} + +void CpuConsumer::setName(const String8& name) { + Mutex::Autolock _l(mMutex); + mName = name; + mBufferQueue->setConsumerName(name); +} + +status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { + status_t err; + + if (!nativeBuffer) return BAD_VALUE; + if (mCurrentLockedBuffers == mMaxLockedBuffers) { + return INVALID_OPERATION; + } + + BufferQueue::BufferItem b; + + Mutex::Autolock _l(mMutex); + + err = mBufferQueue->acquireBuffer(&b); + if (err != OK) { + if (err == BufferQueue::NO_BUFFER_AVAILABLE) { + return BAD_VALUE; + } else { + CC_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err); + return err; + } + } + + int buf = b.mBuf; + + if (b.mGraphicBuffer != NULL) { + if (mBufferPointers[buf] != NULL) { + CC_LOGE("Reallocation of buffer %d while in consumer use!", buf); + mBufferQueue->releaseBuffer(buf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, + Fence::NO_FENCE); + return BAD_VALUE; + } + mBufferSlot[buf] = b.mGraphicBuffer; + } + + if (b.mFence.get()) { + err = b.mFence->wait(Fence::TIMEOUT_NEVER); + if (err != OK) { + CC_LOGE("Failed to wait for fence of acquired buffer: %s (%d)", + strerror(-err), err); + return err; + } + } + + err = mBufferSlot[buf]->lock( + GraphicBuffer::USAGE_SW_READ_OFTEN, + b.mCrop, + &mBufferPointers[buf]); + + if (mBufferPointers[buf] != NULL && err != OK) { + CC_LOGE("Unable to lock buffer for CPU reading: %s (%d)", strerror(-err), + err); + return err; + } + + nativeBuffer->data = reinterpret_cast<uint8_t*>(mBufferPointers[buf]); + nativeBuffer->width = mBufferSlot[buf]->getWidth(); + nativeBuffer->height = mBufferSlot[buf]->getHeight(); + nativeBuffer->format = mBufferSlot[buf]->getPixelFormat(); + nativeBuffer->stride = mBufferSlot[buf]->getStride(); + + nativeBuffer->crop = b.mCrop; + nativeBuffer->transform = b.mTransform; + nativeBuffer->scalingMode = b.mScalingMode; + nativeBuffer->timestamp = b.mTimestamp; + nativeBuffer->frameNumber = b.mFrameNumber; + + mCurrentLockedBuffers++; + + return OK; +} + +status_t CpuConsumer::unlockBuffer(const LockedBuffer &nativeBuffer) { + Mutex::Autolock _l(mMutex); + int buf = 0; + status_t err; + + void *bufPtr = reinterpret_cast<void *>(nativeBuffer.data); + for (; buf < BufferQueue::NUM_BUFFER_SLOTS; buf++) { + if (bufPtr == mBufferPointers[buf]) break; + } + if (buf == BufferQueue::NUM_BUFFER_SLOTS) { + CC_LOGE("%s: Can't find buffer to free", __FUNCTION__); + return BAD_VALUE; + } + + mBufferPointers[buf] = NULL; + err = mBufferSlot[buf]->unlock(); + if (err != OK) { + CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__, buf); + return err; + } + err = mBufferQueue->releaseBuffer(buf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, + Fence::NO_FENCE); + if (err == BufferQueue::STALE_BUFFER_SLOT) { + freeBufferLocked(buf); + } else if (err != OK) { + CC_LOGE("%s: Unable to release graphic buffer %d to queue", __FUNCTION__, + buf); + return err; + } + + mCurrentLockedBuffers--; + + return OK; +} + +void CpuConsumer::setFrameAvailableListener( + const sp<FrameAvailableListener>& listener) { + CC_LOGV("setFrameAvailableListener"); + Mutex::Autolock lock(mMutex); + mFrameAvailableListener = listener; +} + + +void CpuConsumer::onFrameAvailable() { + CC_LOGV("onFrameAvailable"); + sp<FrameAvailableListener> listener; + { // scope for the lock + Mutex::Autolock _l(mMutex); + listener = mFrameAvailableListener; + } + + if (listener != NULL) { + CC_LOGV("actually calling onFrameAvailable"); + listener->onFrameAvailable(); + } +} + +void CpuConsumer::onBuffersReleased() { + CC_LOGV("onBuffersReleased"); + + Mutex::Autolock lock(mMutex); + + uint32_t mask = 0; + mBufferQueue->getReleasedBuffers(&mask); + for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { + if (mask & (1 << i)) { + freeBufferLocked(i); + } + } + +} + +status_t CpuConsumer::freeBufferLocked(int buf) { + status_t err = OK; + + if (mBufferPointers[buf] != NULL) { + CC_LOGW("Buffer %d freed while locked by consumer", buf); + mBufferPointers[buf] = NULL; + err = mBufferSlot[buf]->unlock(); + if (err != OK) { + CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__, buf); + } + mCurrentLockedBuffers--; + } + mBufferSlot[buf] = NULL; + return err; +} + +} // namespace android diff --git a/libs/gui/ISensorServer.cpp b/libs/gui/ISensorServer.cpp index 7111092..0b76f37 100644 --- a/libs/gui/ISensorServer.cpp +++ b/libs/gui/ISensorServer.cpp @@ -55,7 +55,7 @@ public: int32_t n = reply.readInt32(); v.setCapacity(n); while (n--) { - reply.read(static_cast<Flattenable&>(s)); + reply.read(s); v.add(s); } return v; @@ -84,7 +84,7 @@ status_t BnSensorServer::onTransact( size_t n = v.size(); reply->writeInt32(n); for (size_t i=0 ; i<n ; i++) { - reply->write(static_cast<const Flattenable&>(v[i])); + reply->write(v[i]); } return NO_ERROR; } break; diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 1f1794c..76b23f3 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -68,26 +68,29 @@ public: return interface_cast<IGraphicBufferAlloc>(reply.readStrongBinder()); } - virtual sp<IMemoryHeap> getCblk() const + virtual void setTransactionState( + const Vector<ComposerState>& state, + const Vector<DisplayState>& displays, + uint32_t flags) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - remote()->transact(BnSurfaceComposer::GET_CBLK, data, &reply); - return interface_cast<IMemoryHeap>(reply.readStrongBinder()); - } - - virtual void setTransactionState(const Vector<ComposerState>& state, - int orientation, uint32_t flags) - { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - 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); + { + 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); + } + } + { + Vector<DisplayState>::const_iterator b(displays.begin()); + Vector<DisplayState>::const_iterator e(displays.end()); + data.writeInt32(displays.size()); + for ( ; b != e ; ++b ) { + b->write(data); + } } - data.writeInt32(orientation); data.writeInt32(flags); remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply); } @@ -120,24 +123,6 @@ public: return reply.readInt32(); } - virtual status_t turnElectronBeamOff(int32_t mode) - { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - data.writeInt32(mode); - remote()->transact(BnSurfaceComposer::TURN_ELECTRON_BEAM_OFF, data, &reply); - return reply.readInt32(); - } - - virtual status_t turnElectronBeamOn(int32_t mode) - { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - data.writeInt32(mode); - remote()->transact(BnSurfaceComposer::TURN_ELECTRON_BEAM_ON, data, &reply); - return reply.readInt32(); - } - virtual bool authenticateSurfaceTexture( const sp<ISurfaceTexture>& surfaceTexture) const { @@ -193,6 +178,55 @@ public: result = interface_cast<IDisplayEventConnection>(reply.readStrongBinder()); return result; } + + virtual sp<IBinder> createDisplay() + { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + remote()->transact(BnSurfaceComposer::CREATE_DISPLAY, data, &reply); + return reply.readStrongBinder(); + } + + virtual sp<IBinder> getBuiltInDisplay(int32_t id) + { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + data.writeInt32(id); + remote()->transact(BnSurfaceComposer::GET_BUILT_IN_DISPLAY, data, &reply); + return reply.readStrongBinder(); + } + + virtual void blank() + { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + remote()->transact(BnSurfaceComposer::BLANK, data, &reply); + } + + virtual void unblank() + { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + remote()->transact(BnSurfaceComposer::UNBLANK, data, &reply); + } + + virtual status_t getDisplayInfo(DisplayID dpy, DisplayInfo* info) + { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + data.writeInt32(dpy); + remote()->transact(BnSurfaceComposer::GET_DISPLAY_INFO, data, &reply); + memcpy(info, reply.readInplace(sizeof(DisplayInfo)), sizeof(DisplayInfo)); + return reply.readInt32(); + } + + + virtual void connectDisplay(const sp<ISurfaceTexture> display) { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + data.writeStrongBinder(display->asBinder()); + remote()->transact(BnSurfaceComposer::CONNECT_DISPLAY, data, &reply); + } }; IMPLEMENT_META_INTERFACE(SurfaceComposer, "android.ui.ISurfaceComposer"); @@ -223,19 +257,21 @@ status_t BnSurfaceComposer::onTransact( s.read(data); state.add(s); } - int orientation = data.readInt32(); + count = data.readInt32(); + DisplayState d; + Vector<DisplayState> displays; + displays.setCapacity(count); + for (size_t i=0 ; i<count ; i++) { + d.read(data); + displays.add(d); + } uint32_t flags = data.readInt32(); - setTransactionState(state, orientation, flags); + setTransactionState(state, displays, flags); } break; case BOOT_FINISHED: { CHECK_INTERFACE(ISurfaceComposer, data, reply); bootFinished(); } break; - case GET_CBLK: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IBinder> b = getCblk()->asBinder(); - reply->writeStrongBinder(b); - } break; case CAPTURE_SCREEN: { CHECK_INTERFACE(ISurfaceComposer, data, reply); DisplayID dpy = data.readInt32(); @@ -254,18 +290,6 @@ status_t BnSurfaceComposer::onTransact( reply->writeInt32(f); reply->writeInt32(res); } break; - case TURN_ELECTRON_BEAM_OFF: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - int32_t mode = data.readInt32(); - status_t res = turnElectronBeamOff(mode); - reply->writeInt32(res); - } break; - case TURN_ELECTRON_BEAM_ON: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - int32_t mode = data.readInt32(); - status_t res = turnElectronBeamOn(mode); - reply->writeInt32(res); - } break; case AUTHENTICATE_SURFACE: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp<ISurfaceTexture> surfaceTexture = @@ -279,6 +303,41 @@ status_t BnSurfaceComposer::onTransact( reply->writeStrongBinder(connection->asBinder()); return NO_ERROR; } break; + case CREATE_DISPLAY: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp<IBinder> display(createDisplay()); + reply->writeStrongBinder(display); + return NO_ERROR; + } break; + case GET_BUILT_IN_DISPLAY: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + int32_t id = data.readInt32(); + sp<IBinder> display(getBuiltInDisplay(id)); + reply->writeStrongBinder(display); + return NO_ERROR; + } break; + case BLANK: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + blank(); + } break; + case UNBLANK: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + unblank(); + } break; + case GET_DISPLAY_INFO: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + DisplayInfo info; + DisplayID dpy = data.readInt32(); + status_t result = getDisplayInfo(dpy, &info); + memcpy(reply->writeInplace(sizeof(DisplayInfo)), &info, sizeof(DisplayInfo)); + reply->writeInt32(result); + } break; + case CONNECT_DISPLAY: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp<ISurfaceTexture> surfaceTexture = + interface_cast<ISurfaceTexture>(data.readStrongBinder()); + connectDisplay(surfaceTexture); + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/ISurfaceTexture.cpp b/libs/gui/ISurfaceTexture.cpp index 3eb5e7a..a0b1e74 100644 --- a/libs/gui/ISurfaceTexture.cpp +++ b/libs/gui/ISurfaceTexture.cpp @@ -81,8 +81,8 @@ public: return result; } - virtual status_t dequeueBuffer(int *buf, uint32_t w, uint32_t h, - uint32_t format, uint32_t usage) { + virtual status_t dequeueBuffer(int *buf, sp<Fence>& fence, + uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { Parcel data, reply; data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); data.writeInt32(w); @@ -94,6 +94,12 @@ public: return result; } *buf = reply.readInt32(); + fence.clear(); + bool hasFence = reply.readInt32(); + if (hasFence) { + fence = new Fence(); + reply.read(*fence.get()); + } result = reply.readInt32(); return result; } @@ -103,7 +109,7 @@ public: Parcel data, reply; data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); data.writeInt32(buf); - memcpy(data.writeInplace(sizeof(input)), &input, sizeof(input)); + data.write(input); status_t result = remote()->transact(QUEUE_BUFFER, data, &reply); if (result != NO_ERROR) { return result; @@ -113,10 +119,15 @@ public: return result; } - virtual void cancelBuffer(int buf) { + virtual void cancelBuffer(int buf, sp<Fence> fence) { Parcel data, reply; + bool hasFence = fence.get() && fence->isValid(); data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); data.writeInt32(buf); + data.writeInt32(hasFence); + if (hasFence) { + data.write(*fence.get()); + } remote()->transact(CANCEL_BUFFER, data, &reply); } @@ -205,28 +216,38 @@ status_t BnSurfaceTexture::onTransact( uint32_t format = data.readInt32(); uint32_t usage = data.readInt32(); int buf; - int result = dequeueBuffer(&buf, w, h, format, usage); + sp<Fence> fence; + int result = dequeueBuffer(&buf, fence, w, h, format, usage); + bool hasFence = fence.get() && fence->isValid(); reply->writeInt32(buf); + reply->writeInt32(hasFence); + if (hasFence) { + reply->write(*fence.get()); + } reply->writeInt32(result); return NO_ERROR; } break; case QUEUE_BUFFER: { CHECK_INTERFACE(ISurfaceTexture, data, reply); int buf = data.readInt32(); - QueueBufferInput const* const input = - reinterpret_cast<QueueBufferInput const *>( - data.readInplace(sizeof(QueueBufferInput))); + QueueBufferInput input(data); QueueBufferOutput* const output = reinterpret_cast<QueueBufferOutput *>( reply->writeInplace(sizeof(QueueBufferOutput))); - status_t result = queueBuffer(buf, *input, output); + status_t result = queueBuffer(buf, input, output); reply->writeInt32(result); return NO_ERROR; } break; case CANCEL_BUFFER: { CHECK_INTERFACE(ISurfaceTexture, data, reply); int buf = data.readInt32(); - cancelBuffer(buf); + sp<Fence> fence; + bool hasFence = data.readInt32(); + if (hasFence) { + fence = new Fence(); + data.read(*fence.get()); + } + cancelBuffer(buf, fence); return NO_ERROR; } break; case QUERY: { @@ -268,4 +289,62 @@ status_t BnSurfaceTexture::onTransact( // ---------------------------------------------------------------------------- +static bool isValid(const sp<Fence>& fence) { + return fence.get() && fence->isValid(); +} + +ISurfaceTexture::QueueBufferInput::QueueBufferInput(const Parcel& parcel) { + parcel.read(*this); +} + +size_t ISurfaceTexture::QueueBufferInput::getFlattenedSize() const +{ + return sizeof(timestamp) + + sizeof(crop) + + sizeof(scalingMode) + + sizeof(transform) + + sizeof(bool) + + (isValid(fence) ? fence->getFlattenedSize() : 0); +} + +size_t ISurfaceTexture::QueueBufferInput::getFdCount() const +{ + return isValid(fence) ? fence->getFdCount() : 0; +} + +status_t ISurfaceTexture::QueueBufferInput::flatten(void* buffer, size_t size, + int fds[], size_t count) const +{ + status_t err = NO_ERROR; + bool haveFence = isValid(fence); + char* p = (char*)buffer; + memcpy(p, ×tamp, sizeof(timestamp)); p += sizeof(timestamp); + memcpy(p, &crop, sizeof(crop)); p += sizeof(crop); + memcpy(p, &scalingMode, sizeof(scalingMode)); p += sizeof(scalingMode); + memcpy(p, &transform, sizeof(transform)); p += sizeof(transform); + memcpy(p, &haveFence, sizeof(haveFence)); p += sizeof(haveFence); + if (haveFence) { + err = fence->flatten(p, size - (p - (char*)buffer), fds, count); + } + return err; +} + +status_t ISurfaceTexture::QueueBufferInput::unflatten(void const* buffer, + size_t size, int fds[], size_t count) +{ + status_t err = NO_ERROR; + bool haveFence; + const char* p = (const char*)buffer; + memcpy(×tamp, p, sizeof(timestamp)); p += sizeof(timestamp); + memcpy(&crop, p, sizeof(crop)); p += sizeof(crop); + memcpy(&scalingMode, p, sizeof(scalingMode)); p += sizeof(scalingMode); + memcpy(&transform, p, sizeof(transform)); p += sizeof(transform); + memcpy(&haveFence, p, sizeof(haveFence)); p += sizeof(haveFence); + if (haveFence) { + fence = new Fence(); + err = fence->unflatten(p, size - (p - (const char*)buffer), fds, count); + } + return err; +} + }; // namespace android diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 224c305..e2604f8 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -17,6 +17,7 @@ #include <utils/Errors.h> #include <binder/Parcel.h> #include <gui/ISurfaceComposerClient.h> +#include <gui/ISurfaceTexture.h> #include <private/gui/LayerState.h> namespace android { @@ -25,14 +26,7 @@ status_t layer_state_t::write(Parcel& output) const { status_t err; - size_t len = transparentRegion.write(NULL, 0); - err = output.writeInt32(len); - if (err < NO_ERROR) return err; - - void* buf = output.writeInplace(len); - if (buf == NULL) return NO_MEMORY; - - err = transparentRegion.write(buf, len); + err = output.write(transparentRegion); if (err < NO_ERROR) return err; // NOTE: regions are at the end of the structure @@ -45,11 +39,8 @@ status_t layer_state_t::write(Parcel& output) const status_t layer_state_t::read(const Parcel& input) { status_t err; - size_t len = input.readInt32(); - void const* buf = input.readInplace(len); - if (buf == NULL) return NO_MEMORY; - err = transparentRegion.read(buf); + err = input.read(transparentRegion); if (err < NO_ERROR) return err; // NOTE: regions are at the end of the structure @@ -69,4 +60,28 @@ status_t ComposerState::read(const Parcel& input) { return state.read(input); } + +status_t DisplayState::write(Parcel& output) const { + output.writeStrongBinder(token); + output.writeStrongBinder(surface->asBinder()); + output.writeInt32(what); + output.writeInt32(layerStack); + output.writeInt32(orientation); + output.write(viewport); + output.write(frame); + return NO_ERROR; +} + +status_t DisplayState::read(const Parcel& input) { + token = input.readStrongBinder(); + surface = interface_cast<ISurfaceTexture>(input.readStrongBinder()); + what = input.readInt32(); + layerStack = input.readInt32(); + orientation = input.readInt32(); + input.read(viewport); + input.read(frame); + return NO_ERROR; +} + + }; // namespace android diff --git a/libs/gui/Sensor.cpp b/libs/gui/Sensor.cpp index 5cc76b4..c52a88f 100644 --- a/libs/gui/Sensor.cpp +++ b/libs/gui/Sensor.cpp @@ -98,7 +98,7 @@ int32_t Sensor::getVersion() const { return mVersion; } -size_t Sensor::getFlattenedSize() const +size_t Sensor::getSize() const { return sizeof(int32_t) + ((mName.length() + 3) & ~3) + sizeof(int32_t) + ((mVendor.length() + 3) & ~3) + @@ -107,11 +107,6 @@ size_t Sensor::getFlattenedSize() const sizeof(int32_t); } -size_t Sensor::getFdCount() const -{ - return 0; -} - static inline size_t write(void* buffer, size_t offset, const String8& value) { memcpy(static_cast<char*>(buffer) + offset, value.string(), value.length()); @@ -130,12 +125,8 @@ size_t write(void* buffer, size_t offset, int32_t value) { return sizeof(int32_t); } -status_t Sensor::flatten(void* buffer, size_t size, - int fds[], size_t count) const +status_t Sensor::flatten(void* buffer) const { - if (size < Sensor::getFlattenedSize()) - return -ENOMEM; - size_t offset = 0; offset += write(buffer, offset, int32_t(mName.length())); offset += write(buffer, offset, mName); @@ -149,7 +140,6 @@ status_t Sensor::flatten(void* buffer, size_t size, offset += write(buffer, offset, mResolution); offset += write(buffer, offset, mPower); offset += write(buffer, offset, mMinDelay); - return NO_ERROR; } @@ -171,8 +161,7 @@ size_t read(void const* buffer, size_t offset, int32_t* value) { return sizeof(int32_t); } -status_t Sensor::unflatten(void const* buffer, size_t size, - int fds[], size_t count) +status_t Sensor::unflatten(void const* buffer, size_t size) { int32_t len; size_t offset = 0; @@ -188,7 +177,6 @@ status_t Sensor::unflatten(void const* buffer, size_t size, offset += read(buffer, offset, &mResolution); offset += read(buffer, offset, &mPower); offset += read(buffer, offset, &mMinDelay); - return NO_ERROR; } diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index d7590f0..b9cbfa6 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -122,18 +122,6 @@ status_t SurfaceControl::show(int32_t layer) { const sp<SurfaceComposerClient>& client(mClient); return client->show(mToken, layer); } -status_t SurfaceControl::freeze() { - status_t err = validate(); - if (err < 0) return err; - const sp<SurfaceComposerClient>& client(mClient); - return client->freeze(mToken); -} -status_t SurfaceControl::unfreeze() { - status_t err = validate(); - if (err < 0) return err; - const sp<SurfaceComposerClient>& client(mClient); - return client->unfreeze(mToken); -} status_t SurfaceControl::setFlags(uint32_t flags, uint32_t mask) { status_t err = validate(); if (err < 0) return err; @@ -158,12 +146,6 @@ status_t SurfaceControl::setMatrix(float dsdx, float dtdx, float dsdy, float dtd const sp<SurfaceComposerClient>& client(mClient); return client->setMatrix(mToken, dsdx, dtdx, dsdy, dtdy); } -status_t SurfaceControl::setFreezeTint(uint32_t tint) { - status_t err = validate(); - if (err < 0) return err; - const sp<SurfaceComposerClient>& client(mClient); - return client->setFreezeTint(mToken, tint); -} status_t SurfaceControl::setCrop(const Rect& crop) { status_t err = validate(); if (err < 0) return err; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 8fa2167..1e6e1bd 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -38,7 +38,6 @@ #include <private/gui/ComposerService.h> #include <private/gui/LayerState.h> -#include <private/gui/SharedBufferStack.h> namespace android { // --------------------------------------------------------------------------- @@ -51,33 +50,16 @@ ComposerService::ComposerService() while (getService(name, &mComposerService) != NO_ERROR) { usleep(250000); } - mServerCblkMemory = mComposerService->getCblk(); - mServerCblk = static_cast<surface_flinger_cblk_t volatile *>( - mServerCblkMemory->getBase()); } sp<ISurfaceComposer> ComposerService::getComposerService() { return ComposerService::getInstance().mComposerService; } -surface_flinger_cblk_t const volatile * ComposerService::getControlBlock() { - return ComposerService::getInstance().mServerCblk; -} - -static inline sp<ISurfaceComposer> getComposerService() { - return ComposerService::getComposerService(); -} - -static inline surface_flinger_cblk_t const volatile * get_cblk() { - return ComposerService::getControlBlock(); -} - // --------------------------------------------------------------------------- -// 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) { +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; @@ -85,17 +67,21 @@ int compare_type( const ComposerState& lhs, const ComposerState& rhs) { return 0; } +static inline +int compare_type(const DisplayState& lhs, const DisplayState& rhs) { + return compare_type(lhs.token, rhs.token); +} + class Composer : public Singleton<Composer> { friend class Singleton<Composer>; mutable Mutex mLock; - SortedVector<ComposerState> mStates; - int mOrientation; + SortedVector<ComposerState> mComposerStates; + SortedVector<DisplayState > mDisplayStates; uint32_t mForceSynchronous; Composer() : Singleton<Composer>(), - mOrientation(ISurfaceComposer::eOrientationUnchanged), mForceSynchronous(0) { } @@ -104,7 +90,10 @@ class Composer : public Singleton<Composer> layer_state_t* getLayerStateLocked( const sp<SurfaceComposerClient>& client, SurfaceID id); + DisplayState& getDisplayStateLocked(const sp<IBinder>& token); + public: + sp<IBinder> createDisplay(); status_t setPosition(const sp<SurfaceComposerClient>& client, SurfaceID id, float x, float y); @@ -121,12 +110,17 @@ public: 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); status_t setOrientation(int orientation); status_t setCrop(const sp<SurfaceComposerClient>& client, SurfaceID id, const Rect& crop); + status_t setLayerStack(const sp<SurfaceComposerClient>& client, + SurfaceID id, uint32_t layerStack); + + void setDisplaySurface(const sp<IBinder>& token, const sp<ISurfaceTexture>& surface); + void setDisplayLayerStack(const sp<IBinder>& token, uint32_t layerStack); + void setDisplayOrientation(const sp<IBinder>& token, uint32_t orientation); + void setDisplayViewport(const sp<IBinder>& token, const Rect& viewport); + void setDisplayFrame(const sp<IBinder>& token, const Rect& frame); static void closeGlobalTransaction(bool synchronous) { Composer::getInstance().closeGlobalTransactionImpl(synchronous); @@ -137,20 +131,24 @@ ANDROID_SINGLETON_STATIC_INSTANCE(Composer); // --------------------------------------------------------------------------- +sp<IBinder> Composer::createDisplay() { + return ComposerService::getComposerService()->createDisplay(); +} + void Composer::closeGlobalTransactionImpl(bool synchronous) { - sp<ISurfaceComposer> sm(getComposerService()); + sp<ISurfaceComposer> sm(ComposerService::getComposerService()); Vector<ComposerState> transaction; - int orientation; + Vector<DisplayState> displayTransaction; uint32_t flags = 0; { // scope for the lock Mutex::Autolock _l(mLock); - transaction = mStates; - mStates.clear(); + transaction = mComposerStates; + mComposerStates.clear(); - orientation = mOrientation; - mOrientation = ISurfaceComposer::eOrientationUnchanged; + displayTransaction = mDisplayStates; + mDisplayStates.clear(); if (synchronous || mForceSynchronous) { flags |= ISurfaceComposer::eSynchronous; @@ -158,7 +156,7 @@ void Composer::closeGlobalTransactionImpl(bool synchronous) { mForceSynchronous = false; } - sm->setTransactionState(transaction, orientation, flags); + sm->setTransactionState(transaction, displayTransaction, flags); } layer_state_t* Composer::getLayerStateLocked( @@ -168,13 +166,13 @@ layer_state_t* Composer::getLayerStateLocked( s.client = client->mClient; s.state.surface = id; - ssize_t index = mStates.indexOf(s); + ssize_t index = mComposerStates.indexOf(s); if (index < 0) { // we don't have it, add an initialized layer_state to our list - index = mStates.add(s); + index = mComposerStates.add(s); } - ComposerState* const out = mStates.editArray(); + ComposerState* const out = mComposerStates.editArray(); return &(out[index].state); } @@ -184,7 +182,7 @@ status_t Composer::setPosition(const sp<SurfaceComposerClient>& client, layer_state_t* s = getLayerStateLocked(client, id); if (!s) return BAD_INDEX; - s->what |= ISurfaceComposer::ePositionChanged; + s->what |= layer_state_t::ePositionChanged; s->x = x; s->y = y; return NO_ERROR; @@ -196,7 +194,7 @@ status_t Composer::setSize(const sp<SurfaceComposerClient>& client, layer_state_t* s = getLayerStateLocked(client, id); if (!s) return BAD_INDEX; - s->what |= ISurfaceComposer::eSizeChanged; + s->what |= layer_state_t::eSizeChanged; s->w = w; s->h = h; @@ -212,7 +210,7 @@ status_t Composer::setLayer(const sp<SurfaceComposerClient>& client, layer_state_t* s = getLayerStateLocked(client, id); if (!s) return BAD_INDEX; - s->what |= ISurfaceComposer::eLayerChanged; + s->what |= layer_state_t::eLayerChanged; s->z = z; return NO_ERROR; } @@ -224,7 +222,7 @@ status_t Composer::setFlags(const sp<SurfaceComposerClient>& client, layer_state_t* s = getLayerStateLocked(client, id); if (!s) return BAD_INDEX; - s->what |= ISurfaceComposer::eVisibilityChanged; + s->what |= layer_state_t::eVisibilityChanged; s->flags &= ~mask; s->flags |= (flags & mask); s->mask |= mask; @@ -238,7 +236,7 @@ status_t Composer::setTransparentRegionHint( layer_state_t* s = getLayerStateLocked(client, id); if (!s) return BAD_INDEX; - s->what |= ISurfaceComposer::eTransparentRegionChanged; + s->what |= layer_state_t::eTransparentRegionChanged; s->transparentRegion = transparentRegion; return NO_ERROR; } @@ -249,11 +247,22 @@ status_t Composer::setAlpha(const sp<SurfaceComposerClient>& client, layer_state_t* s = getLayerStateLocked(client, id); if (!s) return BAD_INDEX; - s->what |= ISurfaceComposer::eAlphaChanged; + s->what |= layer_state_t::eAlphaChanged; s->alpha = alpha; return NO_ERROR; } +status_t Composer::setLayerStack(const sp<SurfaceComposerClient>& client, + SurfaceID id, uint32_t layerStack) { + Mutex::Autolock _l(mLock); + layer_state_t* s = getLayerStateLocked(client, id); + if (!s) + return BAD_INDEX; + s->what |= layer_state_t::eLayerStackChanged; + s->layerStack = layerStack; + return NO_ERROR; +} + status_t Composer::setMatrix(const sp<SurfaceComposerClient>& client, SurfaceID id, float dsdx, float dtdx, float dsdy, float dtdy) { @@ -261,7 +270,7 @@ status_t Composer::setMatrix(const sp<SurfaceComposerClient>& client, layer_state_t* s = getLayerStateLocked(client, id); if (!s) return BAD_INDEX; - s->what |= ISurfaceComposer::eMatrixChanged; + s->what |= layer_state_t::eMatrixChanged; layer_state_t::matrix22_t matrix; matrix.dsdx = dsdx; matrix.dtdx = dtdx; @@ -271,36 +280,78 @@ status_t Composer::setMatrix(const sp<SurfaceComposerClient>& client, return NO_ERROR; } -status_t Composer::setFreezeTint(const sp<SurfaceComposerClient>& client, - SurfaceID id, uint32_t tint) { +status_t Composer::setCrop(const sp<SurfaceComposerClient>& client, + SurfaceID id, const Rect& crop) { Mutex::Autolock _l(mLock); layer_state_t* s = getLayerStateLocked(client, id); if (!s) return BAD_INDEX; - s->what |= ISurfaceComposer::eFreezeTintChanged; - s->tint = tint; + s->what |= layer_state_t::eCropChanged; + s->crop = crop; return NO_ERROR; } -status_t Composer::setOrientation(int orientation) { +// --------------------------------------------------------------------------- + +DisplayState& Composer::getDisplayStateLocked(const sp<IBinder>& token) { + DisplayState s; + s.token = token; + ssize_t index = mDisplayStates.indexOf(s); + if (index < 0) { + // we don't have it, add an initialized layer_state to our list + s.what = 0; + index = mDisplayStates.add(s); + } + return mDisplayStates.editItemAt(index); +} + +void Composer::setDisplaySurface(const sp<IBinder>& token, + const sp<ISurfaceTexture>& surface) { Mutex::Autolock _l(mLock); - mOrientation = orientation; + DisplayState& s(getDisplayStateLocked(token)); + s.surface = surface; + s.what |= DisplayState::eSurfaceChanged; +} - // Changing the orientation makes the transaction synchronous. - mForceSynchronous = true; +void Composer::setDisplayLayerStack(const sp<IBinder>& token, + uint32_t layerStack) { + Mutex::Autolock _l(mLock); + DisplayState& s(getDisplayStateLocked(token)); + s.layerStack = layerStack; + s.what |= DisplayState::eLayerStackChanged; +} +void Composer::setDisplayOrientation(const sp<IBinder>& token, + uint32_t orientation) { + Mutex::Autolock _l(mLock); + DisplayState& s(getDisplayStateLocked(token)); + s.orientation = orientation; + s.what |= DisplayState::eOrientationChanged; + mForceSynchronous = true; // TODO: do we actually still need this? +} + +// FIXME: get rid of this eventually +status_t Composer::setOrientation(int orientation) { + sp<ISurfaceComposer> sm(ComposerService::getComposerService()); + sp<IBinder> token(sm->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); + Composer::setDisplayOrientation(token, orientation); return NO_ERROR; } -status_t Composer::setCrop(const sp<SurfaceComposerClient>& client, - SurfaceID id, const Rect& crop) { +void Composer::setDisplayViewport(const sp<IBinder>& token, + const Rect& viewport) { Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; - s->what |= ISurfaceComposer::eCropChanged; - s->crop = crop; - return NO_ERROR; + DisplayState& s(getDisplayStateLocked(token)); + s.viewport = viewport; + s.what |= DisplayState::eViewportChanged; +} + +void Composer::setDisplayFrame(const sp<IBinder>& token, + const Rect& frame) { + Mutex::Autolock _l(mLock); + DisplayState& s(getDisplayStateLocked(token)); + s.frame = frame; + s.what |= DisplayState::eFrameChanged; } // --------------------------------------------------------------------------- @@ -311,7 +362,7 @@ SurfaceComposerClient::SurfaceComposerClient() } void SurfaceComposerClient::onFirstRef() { - sp<ISurfaceComposer> sm(getComposerService()); + sp<ISurfaceComposer> sm(ComposerService::getComposerService()); if (sm != 0) { sp<ISurfaceComposerClient> conn = sm->createConnection(); if (conn != 0) { @@ -336,7 +387,7 @@ sp<IBinder> SurfaceComposerClient::connection() const { status_t SurfaceComposerClient::linkToComposerDeath( const sp<IBinder::DeathRecipient>& recipient, void* cookie, uint32_t flags) { - sp<ISurfaceComposer> sm(getComposerService()); + sp<ISurfaceComposer> sm(ComposerService::getComposerService()); return sm->asBinder()->linkToDeath(recipient, cookie, flags); } @@ -388,6 +439,10 @@ sp<SurfaceControl> SurfaceComposerClient::createSurface( return result; } +sp<IBinder> SurfaceComposerClient::createDisplay() { + return Composer::getInstance().createDisplay(); +} + status_t SurfaceComposerClient::destroySurface(SurfaceID sid) { if (mStatus != NO_ERROR) return mStatus; @@ -415,10 +470,6 @@ status_t SurfaceComposerClient::setCrop(SurfaceID id, const Rect& crop) { return getComposer().setCrop(this, id, crop); } -status_t SurfaceComposerClient::setFreezeTint(SurfaceID id, uint32_t tint) { - return getComposer().setFreezeTint(this, id, tint); -} - status_t SurfaceComposerClient::setPosition(SurfaceID id, float x, float y) { return getComposer().setPosition(this, id, x, y); } @@ -433,26 +484,14 @@ status_t SurfaceComposerClient::setLayer(SurfaceID id, int32_t z) { status_t SurfaceComposerClient::hide(SurfaceID id) { return getComposer().setFlags(this, id, - ISurfaceComposer::eLayerHidden, - ISurfaceComposer::eLayerHidden); + layer_state_t::eLayerHidden, + layer_state_t::eLayerHidden); } status_t SurfaceComposerClient::show(SurfaceID id, int32_t) { return getComposer().setFlags(this, id, 0, - ISurfaceComposer::eLayerHidden); -} - -status_t SurfaceComposerClient::freeze(SurfaceID id) { - return getComposer().setFlags(this, id, - ISurfaceComposer::eLayerFrozen, - ISurfaceComposer::eLayerFrozen); -} - -status_t SurfaceComposerClient::unfreeze(SurfaceID id) { - return getComposer().setFlags(this, id, - 0, - ISurfaceComposer::eLayerFrozen); + layer_state_t::eLayerHidden); } status_t SurfaceComposerClient::setFlags(SurfaceID id, uint32_t flags, @@ -469,6 +508,10 @@ status_t SurfaceComposerClient::setAlpha(SurfaceID id, float alpha) { return getComposer().setAlpha(this, id, alpha); } +status_t SurfaceComposerClient::setLayerStack(SurfaceID id, uint32_t layerStack) { + return getComposer().setLayerStack(this, id, layerStack); +} + status_t SurfaceComposerClient::setMatrix(SurfaceID id, float dsdx, float dtdx, float dsdy, float dtdy) { return getComposer().setMatrix(this, id, dsdx, dtdx, dsdy, dtdy); @@ -482,76 +525,37 @@ status_t SurfaceComposerClient::setOrientation(DisplayID dpy, // ---------------------------------------------------------------------------- -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)); +void SurfaceComposerClient::setDisplaySurface(const sp<IBinder>& token, + const sp<ISurfaceTexture>& surface) { + Composer::getInstance().setDisplaySurface(token, surface); } -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; +void SurfaceComposerClient::setDisplayLayerStack(const sp<IBinder>& token, + uint32_t layerStack) { + Composer::getInstance().setDisplayLayerStack(token, layerStack); } -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; +void SurfaceComposerClient::setDisplayOrientation(const sp<IBinder>& token, + uint32_t orientation) { + Composer::getInstance().setDisplayOrientation(token, orientation); } -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; +void SurfaceComposerClient::setDisplayViewport(const sp<IBinder>& token, + const Rect& viewport) { + Composer::getInstance().setDisplayViewport(token, viewport); } -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; +void SurfaceComposerClient::setDisplayFrame(const sp<IBinder>& token, + const Rect& frame) { + Composer::getInstance().setDisplayFrame(token, frame); } // ---------------------------------------------------------------------------- -status_t SurfaceComposerClient::freezeDisplay(DisplayID dpy, uint32_t flags) -{ - // This has been made a no-op because it can cause Gralloc buffer deadlocks. - return NO_ERROR; -} - -status_t SurfaceComposerClient::unfreezeDisplay(DisplayID dpy, uint32_t flags) +status_t SurfaceComposerClient::getDisplayInfo( + DisplayID dpy, DisplayInfo* info) { - // This has been made a no-op because it can cause Gralloc buffer deadlocks. - return NO_ERROR; + return ComposerService::getComposerService()->getDisplayInfo(dpy, info); } // ---------------------------------------------------------------------------- diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp index 55be4bc..451ccc2 100644 --- a/libs/gui/SurfaceTexture.cpp +++ b/libs/gui/SurfaceTexture.cpp @@ -98,14 +98,10 @@ static float mtxRot270[16] = { static void mtxMul(float out[16], const float a[16], const float b[16]); -// Get an ID that's unique within this process. -static int32_t createProcessUniqueId() { - static volatile int32_t globalCounter = 0; - return android_atomic_inc(&globalCounter); -} SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode, GLenum texTarget, bool useFenceSync, const sp<BufferQueue> &bufferQueue) : + ConsumerBase(bufferQueue == 0 ? new BufferQueue(allowSynchronousMode) : bufferQueue), mCurrentTransform(0), mCurrentTimestamp(0), mFilteringEnabled(true), @@ -118,47 +114,15 @@ SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode, mTexTarget(texTarget), mEglDisplay(EGL_NO_DISPLAY), mEglContext(EGL_NO_CONTEXT), - mAbandoned(false), mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT), mAttached(true) { - // Choose a name using the PID and a process-unique ID. - mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); ST_LOGV("SurfaceTexture"); - if (bufferQueue == 0) { - ST_LOGV("Creating a new BufferQueue"); - mBufferQueue = new BufferQueue(allowSynchronousMode); - } - else { - mBufferQueue = bufferQueue; - } memcpy(mCurrentTransformMatrix, mtxIdentity, sizeof(mCurrentTransformMatrix)); - // Note that we can't create an sp<...>(this) in a ctor that will not keep a - // reference once the ctor ends, as that would cause the refcount of 'this' - // dropping to 0 at the end of the ctor. Since all we need is a wp<...> - // that's what we create. - wp<BufferQueue::ConsumerListener> listener; - sp<BufferQueue::ConsumerListener> proxy; - listener = static_cast<BufferQueue::ConsumerListener*>(this); - proxy = new BufferQueue::ProxyConsumerListener(listener); - - status_t err = mBufferQueue->consumerConnect(proxy); - if (err != NO_ERROR) { - ST_LOGE("SurfaceTexture: error connecting to BufferQueue: %s (%d)", - strerror(-err), err); - } else { - mBufferQueue->setConsumerName(mName); - mBufferQueue->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); - } -} - -SurfaceTexture::~SurfaceTexture() { - ST_LOGV("~SurfaceTexture"); - - abandon(); + mBufferQueue->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); } status_t SurfaceTexture::setBufferCountServer(int bufferCount) { @@ -179,6 +143,42 @@ status_t SurfaceTexture::updateTexImage() { return SurfaceTexture::updateTexImage(NULL); } +status_t SurfaceTexture::acquireBufferLocked(BufferQueue::BufferItem *item) { + status_t err = ConsumerBase::acquireBufferLocked(item); + if (err != NO_ERROR) { + return err; + } + + int slot = item->mBuf; + if (item->mGraphicBuffer != NULL) { + if (mEglSlots[slot].mEglImage != EGL_NO_IMAGE_KHR) { + eglDestroyImageKHR(mEglDisplay, mEglSlots[slot].mEglImage); + mEglSlots[slot].mEglImage = EGL_NO_IMAGE_KHR; + } + } + + // Update the GL texture object. We may have to do this even when + // item.mGraphicBuffer == NULL, if we destroyed the EGLImage when + // detaching from a context but the buffer has not been re-allocated. + EGLImageKHR image = createImage(mEglDisplay, mSlots[slot].mGraphicBuffer); + if (image == EGL_NO_IMAGE_KHR) { + return UNKNOWN_ERROR; + } + mEglSlots[slot].mEglImage = image; + + return NO_ERROR; +} + +status_t SurfaceTexture::releaseBufferLocked(int buf, EGLDisplay display, + EGLSyncKHR eglFence, const sp<Fence>& fence) { + status_t err = ConsumerBase::releaseBufferLocked(buf, mEglDisplay, + eglFence, fence); + + mEglSlots[mCurrentTexture].mEglFence = EGL_NO_SYNC_KHR; + + return err; +} + status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter) { ATRACE_CALL(); ST_LOGV("updateTexImage"); @@ -219,106 +219,74 @@ status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter) { // In asynchronous mode the list is guaranteed to be one buffer // deep, while in synchronous mode we use the oldest buffer. - err = mBufferQueue->acquireBuffer(&item); + err = acquireBufferLocked(&item); if (err == NO_ERROR) { int buf = item.mBuf; - // This buffer was newly allocated, so we need to clean up on our side - if (item.mGraphicBuffer != NULL) { - mEGLSlots[buf].mGraphicBuffer = 0; - if (mEGLSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) { - eglDestroyImageKHR(dpy, mEGLSlots[buf].mEglImage); - mEGLSlots[buf].mEglImage = EGL_NO_IMAGE_KHR; - } - mEGLSlots[buf].mGraphicBuffer = item.mGraphicBuffer; - } // we call the rejecter here, in case the caller has a reason to // not accept this buffer. this is used by SurfaceFlinger to // reject buffers which have the wrong size - if (rejecter && rejecter->reject(mEGLSlots[buf].mGraphicBuffer, item)) { - mBufferQueue->releaseBuffer(buf, dpy, mEGLSlots[buf].mFence); - mEGLSlots[buf].mFence = EGL_NO_SYNC_KHR; + if (rejecter && rejecter->reject(mSlots[buf].mGraphicBuffer, item)) { + releaseBufferLocked(buf, dpy, EGL_NO_SYNC_KHR, item.mFence); glBindTexture(mTexTarget, mTexName); return NO_ERROR; } - // Update the GL texture object. We may have to do this even when - // item.mGraphicBuffer == NULL, if we destroyed the EGLImage when - // detaching from a context but the buffer has not been re-allocated. - EGLImageKHR image = mEGLSlots[buf].mEglImage; - if (image == EGL_NO_IMAGE_KHR) { - if (mEGLSlots[buf].mGraphicBuffer == NULL) { - ST_LOGE("updateTexImage: buffer at slot %d is null", buf); - err = BAD_VALUE; - } else { - image = createImage(dpy, mEGLSlots[buf].mGraphicBuffer); - mEGLSlots[buf].mEglImage = image; - if (image == EGL_NO_IMAGE_KHR) { - // NOTE: if dpy was invalid, createImage() is guaranteed to - // fail. so we'd end up here. - err = UNKNOWN_ERROR; - } - } + GLint error; + while ((error = glGetError()) != GL_NO_ERROR) { + ST_LOGW("updateTexImage: clearing GL error: %#04x", error); } - if (err == NO_ERROR) { - GLint error; - while ((error = glGetError()) != GL_NO_ERROR) { - ST_LOGW("updateTexImage: clearing GL error: %#04x", error); - } - - glBindTexture(mTexTarget, mTexName); - glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image); + EGLImageKHR image = mEglSlots[buf].mEglImage; + glBindTexture(mTexTarget, mTexName); + glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image); - while ((error = glGetError()) != GL_NO_ERROR) { - ST_LOGE("updateTexImage: error binding external texture image %p " - "(slot %d): %#04x", image, buf, error); - err = UNKNOWN_ERROR; - } + while ((error = glGetError()) != GL_NO_ERROR) { + ST_LOGE("updateTexImage: error binding external texture image %p " + "(slot %d): %#04x", image, buf, error); + err = UNKNOWN_ERROR; + } - if (err == NO_ERROR) { - err = syncForReleaseLocked(dpy); - } + if (err == NO_ERROR) { + err = syncForReleaseLocked(dpy); } if (err != NO_ERROR) { // Release the buffer we just acquired. It's not safe to // release the old buffer, so instead we just drop the new frame. - mBufferQueue->releaseBuffer(buf, dpy, mEGLSlots[buf].mFence); - mEGLSlots[buf].mFence = EGL_NO_SYNC_KHR; + releaseBufferLocked(buf, dpy, EGL_NO_SYNC_KHR, item.mFence); return err; } ST_LOGV("updateTexImage: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture, mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0, - buf, item.mGraphicBuffer != NULL ? item.mGraphicBuffer->handle : 0); + buf, mSlots[buf].mGraphicBuffer->handle); // release old buffer if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { - status_t status = mBufferQueue->releaseBuffer(mCurrentTexture, dpy, - mEGLSlots[mCurrentTexture].mFence); - - mEGLSlots[mCurrentTexture].mFence = EGL_NO_SYNC_KHR; - if (status == BufferQueue::STALE_BUFFER_SLOT) { - freeBufferLocked(mCurrentTexture); - } else if (status != NO_ERROR) { - ST_LOGE("updateTexImage: released invalid buffer"); + status_t status = releaseBufferLocked(mCurrentTexture, dpy, + mEglSlots[mCurrentTexture].mEglFence, + mSlots[mCurrentTexture].mFence); + if (status != NO_ERROR && status != BufferQueue::STALE_BUFFER_SLOT) { + ST_LOGE("updateTexImage: failed to release buffer: %s (%d)", + strerror(-status), status); err = status; } } // Update the SurfaceTexture state. mCurrentTexture = buf; - mCurrentTextureBuf = mEGLSlots[buf].mGraphicBuffer; + mCurrentTextureBuf = mSlots[buf].mGraphicBuffer; mCurrentCrop = item.mCrop; mCurrentTransform = item.mTransform; mCurrentScalingMode = item.mScalingMode; mCurrentTimestamp = item.mTimestamp; + mCurrentFence = item.mFence; computeCurrentTransformMatrix(); } else { if (err < 0) { - ALOGE("updateTexImage failed on acquire %d", err); + ST_LOGE("updateTexImage failed on acquire %d", err); } // We always bind the texture even if we don't update its contents. glBindTexture(mTexTarget, mTexName); @@ -328,6 +296,27 @@ status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter) { return err; } +void SurfaceTexture::setReleaseFence(int fenceFd) { + sp<Fence> fence(new Fence(fenceFd)); + if (fenceFd == -1 || mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT) + return; + if (!mSlots[mCurrentTexture].mFence.get()) { + mSlots[mCurrentTexture].mFence = fence; + } else { + sp<Fence> mergedFence = Fence::merge( + String8("SurfaceTexture merged release"), + mSlots[mCurrentTexture].mFence, fence); + if (!mergedFence.get()) { + ST_LOGE("failed to merge release fences"); + // synchronization is broken, the best we can do is hope fences + // signal in order so the new fence will act like a union + mSlots[mCurrentTexture].mFence = fence; + return; + } + mSlots[mCurrentTexture].mFence = mergedFence; + } +} + status_t SurfaceTexture::detachFromContext() { ATRACE_CALL(); ST_LOGV("detachFromContext"); @@ -371,10 +360,10 @@ status_t SurfaceTexture::detachFromContext() { // SurfaceTexture gets attached to a new OpenGL ES context (and thus gets a // new EGLDisplay). for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { - EGLImageKHR img = mEGLSlots[i].mEglImage; + EGLImageKHR img = mEglSlots[i].mEglImage; if (img != EGL_NO_IMAGE_KHR) { eglDestroyImageKHR(mEglDisplay, img); - mEGLSlots[i].mEglImage = EGL_NO_IMAGE_KHR; + mEglSlots[i].mEglImage = EGL_NO_IMAGE_KHR; } } @@ -462,7 +451,7 @@ status_t SurfaceTexture::syncForReleaseLocked(EGLDisplay dpy) { ST_LOGV("syncForReleaseLocked"); if (mUseFenceSync && mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { - EGLSyncKHR fence = mEGLSlots[mCurrentTexture].mFence; + EGLSyncKHR fence = mEglSlots[mCurrentTexture].mEglFence; if (fence != EGL_NO_SYNC_KHR) { // There is already a fence for the current slot. We need to wait // on that before replacing it with another fence to ensure that all @@ -490,7 +479,7 @@ status_t SurfaceTexture::syncForReleaseLocked(EGLDisplay dpy) { return UNKNOWN_ERROR; } glFlush(); - mEGLSlots[mCurrentTexture].mFence = fence; + mEglSlots[mCurrentTexture].mEglFence = fence; } return OK; @@ -587,11 +576,13 @@ void SurfaceTexture::computeCurrentTransformMatrix() { // We know there's no subsampling of any channels, so we // only need to shrink by a half a pixel. shrinkAmount = 0.5; + break; default: // If we don't recognize the format, we must assume the // worst case (that we care about), which is YUV420. shrinkAmount = 1.0; + break; } } @@ -631,13 +622,6 @@ nsecs_t SurfaceTexture::getTimestamp() { return mCurrentTimestamp; } -void SurfaceTexture::setFrameAvailableListener( - const sp<FrameAvailableListener>& listener) { - ST_LOGV("setFrameAvailableListener"); - Mutex::Autolock lock(mMutex); - mFrameAvailableListener = listener; -} - EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy, const sp<GraphicBuffer>& graphicBuffer) { EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer(); @@ -705,6 +689,11 @@ uint32_t SurfaceTexture::getCurrentScalingMode() const { return mCurrentScalingMode; } +sp<Fence> SurfaceTexture::getCurrentFence() const { + Mutex::Autolock lock(mMutex); + return mCurrentFence; +} + bool SurfaceTexture::isSynchronousMode() const { Mutex::Autolock lock(mMutex); return mBufferQueue->isSynchronousMode(); @@ -712,35 +701,21 @@ bool SurfaceTexture::isSynchronousMode() const { void SurfaceTexture::freeBufferLocked(int slotIndex) { ST_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); - mEGLSlots[slotIndex].mGraphicBuffer = 0; if (slotIndex == mCurrentTexture) { mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT; } - EGLImageKHR img = mEGLSlots[slotIndex].mEglImage; + EGLImageKHR img = mEglSlots[slotIndex].mEglImage; if (img != EGL_NO_IMAGE_KHR) { ST_LOGV("destroying EGLImage dpy=%p img=%p", mEglDisplay, img); eglDestroyImageKHR(mEglDisplay, img); } - mEGLSlots[slotIndex].mEglImage = EGL_NO_IMAGE_KHR; + mEglSlots[slotIndex].mEglImage = EGL_NO_IMAGE_KHR; } -void SurfaceTexture::abandon() { - ST_LOGV("abandon"); - Mutex::Autolock lock(mMutex); - - if (!mAbandoned) { - mAbandoned = true; - mCurrentTextureBuf.clear(); - - // destroy all egl buffers - for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { - freeBufferLocked(i); - } - - // disconnect from the BufferQueue - mBufferQueue->consumerDisconnect(); - mBufferQueue.clear(); - } +void SurfaceTexture::abandonLocked() { + ST_LOGV("abandonLocked"); + mCurrentTextureBuf.clear(); + ConsumerBase::abandonLocked(); } void SurfaceTexture::setName(const String8& name) { @@ -772,71 +747,18 @@ status_t SurfaceTexture::setSynchronousMode(bool enabled) { return mBufferQueue->setSynchronousMode(enabled); } -// Used for refactoring, should not be in final interface -sp<BufferQueue> SurfaceTexture::getBufferQueue() const { - Mutex::Autolock lock(mMutex); - return mBufferQueue; -} - -void SurfaceTexture::onFrameAvailable() { - ST_LOGV("onFrameAvailable"); - - sp<FrameAvailableListener> listener; - { // scope for the lock - Mutex::Autolock lock(mMutex); - listener = mFrameAvailableListener; - } - - if (listener != NULL) { - ST_LOGV("actually calling onFrameAvailable"); - listener->onFrameAvailable(); - } -} - -void SurfaceTexture::onBuffersReleased() { - ST_LOGV("onBuffersReleased"); - - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - // Nothing to do if we're already abandoned. - return; - } - - uint32_t mask = 0; - mBufferQueue->getReleasedBuffers(&mask); - for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { - if (mask & (1 << i)) { - freeBufferLocked(i); - } - } -} - -void SurfaceTexture::dump(String8& result) const +void SurfaceTexture::dumpLocked(String8& result, const char* prefix, + char* buffer, size_t size) const { - char buffer[1024]; - dump(result, "", buffer, 1024); -} - -void SurfaceTexture::dump(String8& result, const char* prefix, - char* buffer, size_t SIZE) const -{ - Mutex::Autolock _l(mMutex); - snprintf(buffer, SIZE, "%smTexName=%d, mAbandoned=%d\n", prefix, mTexName, - int(mAbandoned)); + snprintf(buffer, size, + "%smTexName=%d mCurrentTexture=%d\n" + "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n", + prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left, + mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom, + mCurrentTransform); result.append(buffer); - snprintf(buffer, SIZE, - "%snext : {crop=[%d,%d,%d,%d], transform=0x%02x, current=%d}\n", - prefix, mCurrentCrop.left, - mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom, - mCurrentTransform, mCurrentTexture - ); - result.append(buffer); - - if (!mAbandoned) { - mBufferQueue->dump(result, prefix, buffer, SIZE); - } + ConsumerBase::dumpLocked(result, prefix, buffer, size); } static void mtxMul(float out[16], const float a[16], const float b[16]) { diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp index 36a81a6..718fe84 100644 --- a/libs/gui/SurfaceTextureClient.cpp +++ b/libs/gui/SurfaceTextureClient.cpp @@ -23,6 +23,8 @@ #include <utils/Log.h> #include <utils/Trace.h> +#include <ui/Fence.h> + #include <gui/ISurfaceComposer.h> #include <gui/SurfaceComposerClient.h> #include <gui/SurfaceTexture.h> @@ -62,11 +64,15 @@ void SurfaceTextureClient::init() { ANativeWindow::setSwapInterval = hook_setSwapInterval; ANativeWindow::dequeueBuffer = hook_dequeueBuffer; ANativeWindow::cancelBuffer = hook_cancelBuffer; - ANativeWindow::lockBuffer = hook_lockBuffer; ANativeWindow::queueBuffer = hook_queueBuffer; ANativeWindow::query = hook_query; ANativeWindow::perform = hook_perform; + ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED; + ANativeWindow::cancelBuffer_DEPRECATED = hook_cancelBuffer_DEPRECATED; + ANativeWindow::lockBuffer_DEPRECATED = hook_lockBuffer_DEPRECATED; + ANativeWindow::queueBuffer_DEPRECATED = hook_queueBuffer_DEPRECATED; + const_cast<int&>(ANativeWindow::minSwapInterval) = 0; const_cast<int&>(ANativeWindow::maxSwapInterval) = 1; @@ -103,27 +109,54 @@ int SurfaceTextureClient::hook_setSwapInterval(ANativeWindow* window, int interv } int SurfaceTextureClient::hook_dequeueBuffer(ANativeWindow* window, - ANativeWindowBuffer** buffer) { + ANativeWindowBuffer** buffer, int* fenceFd) { SurfaceTextureClient* c = getSelf(window); - return c->dequeueBuffer(buffer); + return c->dequeueBuffer(buffer, fenceFd); } int SurfaceTextureClient::hook_cancelBuffer(ANativeWindow* window, + ANativeWindowBuffer* buffer, int fenceFd) { + SurfaceTextureClient* c = getSelf(window); + return c->cancelBuffer(buffer, fenceFd); +} + +int SurfaceTextureClient::hook_queueBuffer(ANativeWindow* window, + ANativeWindowBuffer* buffer, int fenceFd) { + SurfaceTextureClient* c = getSelf(window); + return c->queueBuffer(buffer, fenceFd); +} + +int SurfaceTextureClient::hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, + ANativeWindowBuffer** buffer) { + SurfaceTextureClient* c = getSelf(window); + int fenceFd = -1; + int result = c->dequeueBuffer(buffer, &fenceFd); + sp<Fence> fence(new Fence(fenceFd)); + int waitResult = fence->wait(Fence::TIMEOUT_NEVER); + if (waitResult != OK) { + ALOGE("hook_dequeueBuffer_DEPRECATED: Fence::wait returned an " + "error: %d", waitResult); + return waitResult; + } + return result; +} + +int SurfaceTextureClient::hook_cancelBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer) { SurfaceTextureClient* c = getSelf(window); - return c->cancelBuffer(buffer); + return c->cancelBuffer(buffer, -1); } -int SurfaceTextureClient::hook_lockBuffer(ANativeWindow* window, +int SurfaceTextureClient::hook_lockBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer) { SurfaceTextureClient* c = getSelf(window); - return c->lockBuffer(buffer); + return c->lockBuffer_DEPRECATED(buffer); } -int SurfaceTextureClient::hook_queueBuffer(ANativeWindow* window, +int SurfaceTextureClient::hook_queueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer) { SurfaceTextureClient* c = getSelf(window); - return c->queueBuffer(buffer); + return c->queueBuffer(buffer, -1); } int SurfaceTextureClient::hook_query(const ANativeWindow* window, @@ -157,14 +190,16 @@ int SurfaceTextureClient::setSwapInterval(int interval) { return res; } -int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer) { +int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer, + int* fenceFd) { ATRACE_CALL(); ALOGV("SurfaceTextureClient::dequeueBuffer"); Mutex::Autolock lock(mMutex); int buf = -1; int reqW = mReqWidth ? mReqWidth : mUserWidth; int reqH = mReqHeight ? mReqHeight : mUserHeight; - status_t result = mSurfaceTexture->dequeueBuffer(&buf, reqW, reqH, + sp<Fence> fence; + status_t result = mSurfaceTexture->dequeueBuffer(&buf, fence, reqW, reqH, mReqFormat, mReqUsage); if (result < 0) { ALOGV("dequeueBuffer: ISurfaceTexture::dequeueBuffer(%d, %d, %d, %d)" @@ -185,11 +220,25 @@ int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer) { return result; } } + + if (fence.get()) { + *fenceFd = fence->dup(); + if (*fenceFd == -1) { + ALOGE("dequeueBuffer: error duping fence: %d", errno); + // dup() should never fail; something is badly wrong. Soldier on + // and hope for the best; the worst that should happen is some + // visible corruption that lasts until the next frame. + } + } else { + *fenceFd = -1; + } + *buffer = gbuf.get(); return OK; } -int SurfaceTextureClient::cancelBuffer(android_native_buffer_t* buffer) { +int SurfaceTextureClient::cancelBuffer(android_native_buffer_t* buffer, + int fenceFd) { ATRACE_CALL(); ALOGV("SurfaceTextureClient::cancelBuffer"); Mutex::Autolock lock(mMutex); @@ -197,7 +246,8 @@ int SurfaceTextureClient::cancelBuffer(android_native_buffer_t* buffer) { if (i < 0) { return i; } - mSurfaceTexture->cancelBuffer(i); + sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : NULL); + mSurfaceTexture->cancelBuffer(i, fence); return OK; } @@ -214,13 +264,13 @@ int SurfaceTextureClient::getSlotFromBufferLocked( return BAD_VALUE; } -int SurfaceTextureClient::lockBuffer(android_native_buffer_t* buffer) { +int SurfaceTextureClient::lockBuffer_DEPRECATED(android_native_buffer_t* buffer) { ALOGV("SurfaceTextureClient::lockBuffer"); Mutex::Autolock lock(mMutex); return OK; } -int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer) { +int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { ATRACE_CALL(); ALOGV("SurfaceTextureClient::queueBuffer"); Mutex::Autolock lock(mMutex); @@ -237,13 +287,15 @@ int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer) { return i; } + // Make sure the crop rectangle is entirely inside the buffer. Rect crop; mCrop.intersect(Rect(buffer->width, buffer->height), &crop); + sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : NULL); ISurfaceTexture::QueueBufferOutput output; ISurfaceTexture::QueueBufferInput input(timestamp, crop, mScalingMode, - mTransform); + mTransform, fence); status_t err = mSurfaceTexture->queueBuffer(i, input, &output); if (err != OK) { ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err); @@ -692,78 +744,83 @@ status_t SurfaceTextureClient::lock( } ANativeWindowBuffer* out; - status_t err = dequeueBuffer(&out); + int fenceFd = -1; + status_t err = dequeueBuffer(&out, &fenceFd); ALOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err)); if (err == NO_ERROR) { sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out)); - err = lockBuffer(backBuffer.get()); - ALOGE_IF(err, "lockBuffer (handle=%p) failed (%s)", - backBuffer->handle, strerror(-err)); - if (err == NO_ERROR) { - const Rect bounds(backBuffer->width, backBuffer->height); - - Region newDirtyRegion; - if (inOutDirtyBounds) { - newDirtyRegion.set(static_cast<Rect const&>(*inOutDirtyBounds)); - newDirtyRegion.andSelf(bounds); - } else { - newDirtyRegion.set(bounds); - } + sp<Fence> fence(new Fence(fenceFd)); - // figure out if we can copy the frontbuffer back - const sp<GraphicBuffer>& frontBuffer(mPostedBuffer); - const bool canCopyBack = (frontBuffer != 0 && - backBuffer->width == frontBuffer->width && - backBuffer->height == frontBuffer->height && - backBuffer->format == frontBuffer->format); - - if (canCopyBack) { - // copy the area that is invalid and not repainted this round - const Region copyback(mDirtyRegion.subtract(newDirtyRegion)); - if (!copyback.isEmpty()) - copyBlt(backBuffer, frontBuffer, copyback); - } else { - // if we can't copy-back anything, modify the user's dirty - // region to make sure they redraw the whole buffer - newDirtyRegion.set(bounds); - mDirtyRegion.clear(); - Mutex::Autolock lock(mMutex); - for (size_t i=0 ; i<NUM_BUFFER_SLOTS ; i++) { - mSlots[i].dirtyRegion.clear(); - } - } + err = fence->wait(Fence::TIMEOUT_NEVER); + if (err != OK) { + ALOGE("Fence::wait failed (%s)", strerror(-err)); + cancelBuffer(out, fenceFd); + return err; + } + const Rect bounds(backBuffer->width, backBuffer->height); - { // scope for the lock - Mutex::Autolock lock(mMutex); - int backBufferSlot(getSlotFromBufferLocked(backBuffer.get())); - if (backBufferSlot >= 0) { - Region& dirtyRegion(mSlots[backBufferSlot].dirtyRegion); - mDirtyRegion.subtract(dirtyRegion); - dirtyRegion = newDirtyRegion; - } - } + Region newDirtyRegion; + if (inOutDirtyBounds) { + newDirtyRegion.set(static_cast<Rect const&>(*inOutDirtyBounds)); + newDirtyRegion.andSelf(bounds); + } else { + newDirtyRegion.set(bounds); + } - mDirtyRegion.orSelf(newDirtyRegion); - if (inOutDirtyBounds) { - *inOutDirtyBounds = newDirtyRegion.getBounds(); + // figure out if we can copy the frontbuffer back + const sp<GraphicBuffer>& frontBuffer(mPostedBuffer); + const bool canCopyBack = (frontBuffer != 0 && + backBuffer->width == frontBuffer->width && + backBuffer->height == frontBuffer->height && + backBuffer->format == frontBuffer->format); + + if (canCopyBack) { + // copy the area that is invalid and not repainted this round + const Region copyback(mDirtyRegion.subtract(newDirtyRegion)); + if (!copyback.isEmpty()) + copyBlt(backBuffer, frontBuffer, copyback); + } else { + // if we can't copy-back anything, modify the user's dirty + // region to make sure they redraw the whole buffer + newDirtyRegion.set(bounds); + mDirtyRegion.clear(); + Mutex::Autolock lock(mMutex); + for (size_t i=0 ; i<NUM_BUFFER_SLOTS ; i++) { + mSlots[i].dirtyRegion.clear(); } + } - void* vaddr; - status_t res = backBuffer->lock( - GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - newDirtyRegion.bounds(), &vaddr); - ALOGW_IF(res, "failed locking buffer (handle = %p)", - backBuffer->handle); + { // scope for the lock + Mutex::Autolock lock(mMutex); + int backBufferSlot(getSlotFromBufferLocked(backBuffer.get())); + if (backBufferSlot >= 0) { + Region& dirtyRegion(mSlots[backBufferSlot].dirtyRegion); + mDirtyRegion.subtract(dirtyRegion); + dirtyRegion = newDirtyRegion; + } + } - mLockedBuffer = backBuffer; - outBuffer->width = backBuffer->width; - outBuffer->height = backBuffer->height; - outBuffer->stride = backBuffer->stride; - outBuffer->format = backBuffer->format; - outBuffer->bits = vaddr; + mDirtyRegion.orSelf(newDirtyRegion); + if (inOutDirtyBounds) { + *inOutDirtyBounds = newDirtyRegion.getBounds(); } + + void* vaddr; + status_t res = backBuffer->lock( + GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + newDirtyRegion.bounds(), &vaddr); + + ALOGW_IF(res, "failed locking buffer (handle = %p)", + backBuffer->handle); + + mLockedBuffer = backBuffer; + outBuffer->width = backBuffer->width; + outBuffer->height = backBuffer->height; + outBuffer->stride = backBuffer->stride; + outBuffer->format = backBuffer->format; + outBuffer->bits = vaddr; } return err; } @@ -778,7 +835,7 @@ status_t SurfaceTextureClient::unlockAndPost() status_t err = mLockedBuffer->unlock(); ALOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle); - err = queueBuffer(mLockedBuffer.get()); + err = queueBuffer(mLockedBuffer.get(), -1); ALOGE_IF(err, "queueBuffer (handle=%p) failed (%s)", mLockedBuffer->handle, strerror(-err)); diff --git a/libs/gui/tests/Android.mk b/libs/gui/tests/Android.mk index 741534b..e8863d3 100644 --- a/libs/gui/tests/Android.mk +++ b/libs/gui/tests/Android.mk @@ -2,14 +2,15 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) -LOCAL_MODULE := SurfaceTexture_test +LOCAL_MODULE := libgui_test LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := \ - Surface_test.cpp \ + CpuConsumer_test.cpp \ SurfaceTextureClient_test.cpp \ SurfaceTexture_test.cpp \ + Surface_test.cpp \ LOCAL_SHARED_LIBRARIES := \ libEGL \ @@ -18,6 +19,7 @@ LOCAL_SHARED_LIBRARIES := \ libcutils \ libgui \ libstlport \ + libsync \ libui \ libutils \ diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp new file mode 100644 index 0000000..371fb8b --- /dev/null +++ b/libs/gui/tests/CpuConsumer_test.cpp @@ -0,0 +1,503 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "CpuConsumer_test" +//#define LOG_NDEBUG 0 +//#define LOG_NNDEBUG 0 + +#ifdef LOG_NNDEBUG +#define ALOGVV(...) ALOGV(__VA_ARGS__) +#else +#define ALOGVV(...) ((void)0) +#endif + +#include <gtest/gtest.h> +#include <gui/CpuConsumer.h> +#include <gui/SurfaceTextureClient.h> +#include <ui/GraphicBuffer.h> +#include <utils/String8.h> +#include <utils/Thread.h> +#include <utils/Mutex.h> +#include <utils/Condition.h> + +#include <ui/FramebufferNativeWindow.h> + +namespace android { + +struct CpuConsumerTestParams { + uint32_t width; + uint32_t height; + int maxLockedBuffers; + PixelFormat format; +}; + +::std::ostream& operator<<(::std::ostream& os, const CpuConsumerTestParams& p) { + return os << "[ (" << p.width << ", " << p.height << "), B:" + << p.maxLockedBuffers << ", F:0x" + << ::std::hex << p.format << "]"; +} + +class CpuConsumerTest : public ::testing::TestWithParam<CpuConsumerTestParams> { +protected: + + virtual void SetUp() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + CpuConsumerTestParams params = GetParam(); + ALOGV("** Starting test %s (%d x %d, %d, 0x%x)", + test_info->name(), + params.width, params.height, + params.maxLockedBuffers, params.format); + mCC = new CpuConsumer(params.maxLockedBuffers); + String8 name("CpuConsumer_Under_Test"); + mCC->setName(name); + mSTC = new SurfaceTextureClient(mCC->getProducerInterface()); + mANW = mSTC; + } + + virtual void TearDown() { + mANW.clear(); + mSTC.clear(); + mCC.clear(); + } + + class FrameWaiter : public CpuConsumer::FrameAvailableListener { + public: + FrameWaiter(): + mPendingFrames(0) { + } + + void waitForFrame() { + Mutex::Autolock lock(mMutex); + while (mPendingFrames == 0) { + mCondition.wait(mMutex); + } + mPendingFrames--; + } + + virtual void onFrameAvailable() { + Mutex::Autolock lock(mMutex); + mPendingFrames++; + mCondition.signal(); + } + + int mPendingFrames; + Mutex mMutex; + Condition mCondition; + }; + + // Note that SurfaceTexture will lose the notifications + // onBuffersReleased and onFrameAvailable as there is currently + // no way to forward the events. This DisconnectWaiter will not let the + // disconnect finish until finishDisconnect() is called. It will + // also block until a disconnect is called + class DisconnectWaiter : public BufferQueue::ConsumerListener { + public: + DisconnectWaiter () : + mWaitForDisconnect(false), + mPendingFrames(0) { + } + + void waitForFrame() { + Mutex::Autolock lock(mMutex); + while (mPendingFrames == 0) { + mFrameCondition.wait(mMutex); + } + mPendingFrames--; + } + + virtual void onFrameAvailable() { + Mutex::Autolock lock(mMutex); + mPendingFrames++; + mFrameCondition.signal(); + } + + virtual void onBuffersReleased() { + Mutex::Autolock lock(mMutex); + while (!mWaitForDisconnect) { + mDisconnectCondition.wait(mMutex); + } + } + + void finishDisconnect() { + Mutex::Autolock lock(mMutex); + mWaitForDisconnect = true; + mDisconnectCondition.signal(); + } + + private: + Mutex mMutex; + + bool mWaitForDisconnect; + Condition mDisconnectCondition; + + int mPendingFrames; + Condition mFrameCondition; + }; + + sp<CpuConsumer> mCC; + sp<SurfaceTextureClient> mSTC; + sp<ANativeWindow> mANW; +}; + +#define ASSERT_NO_ERROR(err, msg) \ + ASSERT_EQ(NO_ERROR, err) << msg << strerror(-err) + +void checkPixel(const CpuConsumer::LockedBuffer &buf, + uint32_t x, uint32_t y, uint32_t r, uint32_t g, uint32_t b) { + // Ignores components that don't exist for given pixel + switch(buf.format) { + case HAL_PIXEL_FORMAT_RAW_SENSOR: { + String8 msg; + uint16_t *bPtr = (uint16_t*)buf.data; + bPtr += y * buf.stride + x; + // GRBG Bayer mosaic; only check the matching channel + switch( ((y & 1) << 1) | (x & 1) ) { + case 0: // G + case 3: // G + EXPECT_EQ(g, *bPtr); + break; + case 1: // R + EXPECT_EQ(r, *bPtr); + break; + case 2: // B + EXPECT_EQ(b, *bPtr); + break; + } + break; + } + default: { + ADD_FAILURE() << "Unknown format for check:" << buf.format; + break; + } + } +} + +// Fill a YV12 buffer with a multi-colored checkerboard pattern +void fillYV12Buffer(uint8_t* buf, int w, int h, int stride); + +// Fill a RAW sensor buffer with a multi-colored checkerboard pattern. +// Assumes GRBG mosaic ordering. Result should be a grid in a 2x2 pattern +// of [ R, B; G, W] +void fillBayerRawBuffer(uint8_t* buf, int w, int h, int stride) { + ALOGVV("fillBayerRawBuffer: %p with %d x %d, stride %d", buf, w, h ,stride); + // Blocks need to be even-width/height, aim for 8-wide otherwise + const int blockWidth = (w > 16 ? w / 8 : 2) & ~0x1; + const int blockHeight = (h > 16 ? h / 8 : 2) & ~0x1; + for (int y = 0; y < h; y+=2) { + uint16_t *bPtr1 = ((uint16_t*)buf) + stride*y; + uint16_t *bPtr2 = bPtr1 + stride; + for (int x = 0; x < w; x+=2) { + int blockX = (x / blockWidth ) & 1; + int blockY = (y / blockHeight) & 1; + unsigned short r = (blockX == blockY) ? 1000 : 200; + unsigned short g = blockY ? 1000: 200; + unsigned short b = blockX ? 1000: 200; + // GR row + *bPtr1++ = g; + *bPtr1++ = r; + // BG row + *bPtr2++ = b; + *bPtr2++ = g; + } + } + +} + +void checkBayerRawBuffer(const CpuConsumer::LockedBuffer &buf) { + uint32_t w = buf.width; + uint32_t h = buf.height; + const int blockWidth = (w > 16 ? w / 8 : 2) & ~0x1; + const int blockHeight = (h > 16 ? h / 8 : 2) & ~0x1; + const int blockRows = h / blockHeight; + const int blockCols = w / blockWidth; + + // Top-left square is red + checkPixel(buf, 0, 0, 1000, 200, 200); + checkPixel(buf, 1, 0, 1000, 200, 200); + checkPixel(buf, 0, 1, 1000, 200, 200); + checkPixel(buf, 1, 1, 1000, 200, 200); + + // One-right square is blue + checkPixel(buf, blockWidth, 0, 200, 200, 1000); + checkPixel(buf, blockWidth + 1, 0, 200, 200, 1000); + checkPixel(buf, blockWidth, 1, 200, 200, 1000); + checkPixel(buf, blockWidth + 1, 1, 200, 200, 1000); + + // One-down square is green + checkPixel(buf, 0, blockHeight, 200, 1000, 200); + checkPixel(buf, 1, blockHeight, 200, 1000, 200); + checkPixel(buf, 0, blockHeight + 1, 200, 1000, 200); + checkPixel(buf, 1, blockHeight + 1, 200, 1000, 200); + + // One-diag square is white + checkPixel(buf, blockWidth, blockHeight, 1000, 1000, 1000); + checkPixel(buf, blockWidth + 1, blockHeight, 1000, 1000, 1000); + checkPixel(buf, blockWidth, blockHeight + 1, 1000, 1000, 1000); + checkPixel(buf, blockWidth + 1, blockHeight + 1, 1000, 1000, 1000); + + // Test bottom-right pixel + const int maxBlockX = ((w-1) / blockWidth) & 0x1; + const int maxBlockY = ((w-1) / blockHeight) & 0x1; + unsigned short maxR = (maxBlockX == maxBlockY) ? 1000 : 200; + unsigned short maxG = maxBlockY ? 1000: 200; + unsigned short maxB = maxBlockX ? 1000: 200; + checkPixel(buf, w-1, h-1, maxR, maxG, maxB); +} + +void fillYV12BufferRect(uint8_t* buf, int w, int h, int stride, + const android_native_rect_t& rect); + +void fillRGBA8Buffer(uint8_t* buf, int w, int h, int stride); + +void fillRGBA8BufferSolid(uint8_t* buf, int w, int h, int stride, uint8_t r, + uint8_t g, uint8_t b, uint8_t a); + +// Configures the ANativeWindow producer-side interface based on test parameters +void configureANW(const sp<ANativeWindow>& anw, + const CpuConsumerTestParams& params, + int maxBufferSlack) { + status_t err; + err = native_window_set_buffers_geometry(anw.get(), + params.width, params.height, params.format); + ASSERT_NO_ERROR(err, "set_buffers_geometry error: "); + + err = native_window_set_usage(anw.get(), + GRALLOC_USAGE_SW_WRITE_OFTEN); + ASSERT_NO_ERROR(err, "set_usage error: "); + + int minUndequeuedBuffers; + err = anw.get()->query(anw.get(), + NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, + &minUndequeuedBuffers); + ASSERT_NO_ERROR(err, "query error: "); + + ALOGVV("Setting buffer count to %d", + maxBufferSlack + 1 + minUndequeuedBuffers); + err = native_window_set_buffer_count(anw.get(), + maxBufferSlack + 1 + minUndequeuedBuffers); + ASSERT_NO_ERROR(err, "set_buffer_count error: "); + +} + +// Produce one frame of image data; assumes format and resolution configuration +// is already done. +void produceOneFrame(const sp<ANativeWindow>& anw, + const CpuConsumerTestParams& params, + int64_t timestamp, uint32_t *stride) { + status_t err; + ANativeWindowBuffer* anb; + ALOGVV("Dequeue buffer from %p", anw.get()); + err = native_window_dequeue_buffer_and_wait(anw.get(), &anb); + ASSERT_NO_ERROR(err, "dequeueBuffer error: "); + + ASSERT_TRUE(anb != NULL); + + sp<GraphicBuffer> buf(new GraphicBuffer(anb, false)); + + *stride = buf->getStride(); + uint8_t* img = NULL; + + ALOGVV("Lock buffer from %p for write", anw.get()); + err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); + ASSERT_NO_ERROR(err, "lock error: "); + + switch (params.format) { + case HAL_PIXEL_FORMAT_YV12: + fillYV12Buffer(img, params.width, params.height, *stride); + break; + case HAL_PIXEL_FORMAT_RAW_SENSOR: + fillBayerRawBuffer(img, params.width, params.height, buf->getStride()); + break; + default: + FAIL() << "Unknown pixel format under test!"; + break; + } + ALOGVV("Unlock buffer from %p", anw.get()); + err = buf->unlock(); + ASSERT_NO_ERROR(err, "unlock error: "); + + ALOGVV("Set timestamp to %p", anw.get()); + err = native_window_set_buffers_timestamp(anw.get(), timestamp); + ASSERT_NO_ERROR(err, "set_buffers_timestamp error: "); + + ALOGVV("Queue buffer to %p", anw.get()); + err = anw->queueBuffer(anw.get(), buf->getNativeBuffer(), -1); + ASSERT_NO_ERROR(err, "queueBuffer error:"); +}; + +TEST_P(CpuConsumerTest, FromCpuSingle) { + status_t err; + CpuConsumerTestParams params = GetParam(); + + // Set up + + ASSERT_NO_FATAL_FAILURE(configureANW(mANW, params, 1)); + + // Produce + + const int64_t time = 12345678L; + uint32_t stride; + ASSERT_NO_FATAL_FAILURE(produceOneFrame(mANW, params, time, + &stride)); + + // Consume + + CpuConsumer::LockedBuffer b; + err = mCC->lockNextBuffer(&b); + ASSERT_NO_ERROR(err, "getNextBuffer error: "); + + ASSERT_TRUE(b.data != NULL); + EXPECT_EQ(params.width, b.width); + EXPECT_EQ(params.height, b.height); + EXPECT_EQ(params.format, b.format); + EXPECT_EQ(stride, b.stride); + EXPECT_EQ(time, b.timestamp); + + checkBayerRawBuffer(b); + mCC->unlockBuffer(b); +} + +TEST_P(CpuConsumerTest, FromCpuManyInQueue) { + status_t err; + CpuConsumerTestParams params = GetParam(); + + const int numInQueue = 5; + // Set up + + ASSERT_NO_FATAL_FAILURE(configureANW(mANW, params, numInQueue)); + + // Produce + + const int64_t time[numInQueue] = { 1L, 2L, 3L, 4L, 5L}; + uint32_t stride[numInQueue]; + + for (int i = 0; i < numInQueue; i++) { + ALOGV("Producing frame %d", i); + ASSERT_NO_FATAL_FAILURE(produceOneFrame(mANW, params, time[i], + &stride[i])); + } + + // Consume + + for (int i = 0; i < numInQueue; i++) { + ALOGV("Consuming frame %d", i); + CpuConsumer::LockedBuffer b; + err = mCC->lockNextBuffer(&b); + ASSERT_NO_ERROR(err, "getNextBuffer error: "); + + ASSERT_TRUE(b.data != NULL); + EXPECT_EQ(params.width, b.width); + EXPECT_EQ(params.height, b.height); + EXPECT_EQ(params.format, b.format); + EXPECT_EQ(stride[i], b.stride); + EXPECT_EQ(time[i], b.timestamp); + + checkBayerRawBuffer(b); + + mCC->unlockBuffer(b); + } +} + +TEST_P(CpuConsumerTest, FromCpuLockMax) { + status_t err; + CpuConsumerTestParams params = GetParam(); + + // Set up + + ASSERT_NO_FATAL_FAILURE(configureANW(mANW, params, params.maxLockedBuffers + 1)); + + // Produce + + const int64_t time = 1234L; + uint32_t stride; + + for (int i = 0; i < params.maxLockedBuffers + 1; i++) { + ALOGV("Producing frame %d", i); + ASSERT_NO_FATAL_FAILURE(produceOneFrame(mANW, params, time, + &stride)); + } + + // Consume + + CpuConsumer::LockedBuffer *b = new CpuConsumer::LockedBuffer[params.maxLockedBuffers]; + for (int i = 0; i < params.maxLockedBuffers; i++) { + ALOGV("Locking frame %d", i); + err = mCC->lockNextBuffer(&b[i]); + ASSERT_NO_ERROR(err, "getNextBuffer error: "); + + ASSERT_TRUE(b[i].data != NULL); + EXPECT_EQ(params.width, b[i].width); + EXPECT_EQ(params.height, b[i].height); + EXPECT_EQ(params.format, b[i].format); + EXPECT_EQ(stride, b[i].stride); + EXPECT_EQ(time, b[i].timestamp); + + checkBayerRawBuffer(b[i]); + } + + ALOGV("Locking frame %d (too many)", params.maxLockedBuffers); + CpuConsumer::LockedBuffer bTooMuch; + err = mCC->lockNextBuffer(&bTooMuch); + ASSERT_TRUE(err == INVALID_OPERATION) << "Allowing too many locks"; + + ALOGV("Unlocking frame 0"); + err = mCC->unlockBuffer(b[0]); + ASSERT_NO_ERROR(err, "Could not unlock buffer 0: "); + + ALOGV("Locking frame %d (should work now)", params.maxLockedBuffers); + err = mCC->lockNextBuffer(&bTooMuch); + ASSERT_NO_ERROR(err, "Did not allow new lock after unlock"); + + ASSERT_TRUE(bTooMuch.data != NULL); + EXPECT_EQ(params.width, bTooMuch.width); + EXPECT_EQ(params.height, bTooMuch.height); + EXPECT_EQ(params.format, bTooMuch.format); + EXPECT_EQ(stride, bTooMuch.stride); + EXPECT_EQ(time, bTooMuch.timestamp); + + checkBayerRawBuffer(bTooMuch); + + ALOGV("Unlocking extra buffer"); + err = mCC->unlockBuffer(bTooMuch); + ASSERT_NO_ERROR(err, "Could not unlock extra buffer: "); + + ALOGV("Locking frame %d (no more available)", params.maxLockedBuffers + 1); + err = mCC->lockNextBuffer(&b[0]); + ASSERT_EQ(BAD_VALUE, err) << "Not out of buffers somehow"; + + for (int i = 1; i < params.maxLockedBuffers; i++) { + mCC->unlockBuffer(b[i]); + } + + delete[] b; + +} + +CpuConsumerTestParams rawTestSets[] = { + { 512, 512, 1, HAL_PIXEL_FORMAT_RAW_SENSOR}, + { 512, 512, 3, HAL_PIXEL_FORMAT_RAW_SENSOR}, + { 2608, 1960, 1, HAL_PIXEL_FORMAT_RAW_SENSOR}, + { 2608, 1960, 3, HAL_PIXEL_FORMAT_RAW_SENSOR}, + { 100, 100, 1, HAL_PIXEL_FORMAT_RAW_SENSOR}, + { 100, 100, 3, HAL_PIXEL_FORMAT_RAW_SENSOR} +}; + +INSTANTIATE_TEST_CASE_P(RawTests, + CpuConsumerTest, + ::testing::ValuesIn(rawTestSets)); + +} // namespace android diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp index 7d8dd33..59b9efd 100644 --- a/libs/gui/tests/SurfaceTextureClient_test.cpp +++ b/libs/gui/tests/SurfaceTextureClient_test.cpp @@ -180,129 +180,129 @@ TEST_F(SurfaceTextureClientTest, BufferGeometryInvalidSizesFail) { TEST_F(SurfaceTextureClientTest, DefaultGeometryValues) { ANativeWindowBuffer* buf; - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf)); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); EXPECT_EQ(1, buf->width); EXPECT_EQ(1, buf->height); EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format); - ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf)); + ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1)); } TEST_F(SurfaceTextureClientTest, BufferGeometryCanBeSet) { ANativeWindowBuffer* buf; EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 16, 8, PIXEL_FORMAT_RGB_565)); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf)); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); EXPECT_EQ(16, buf->width); EXPECT_EQ(8, buf->height); EXPECT_EQ(PIXEL_FORMAT_RGB_565, buf->format); - ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf)); + ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1)); } TEST_F(SurfaceTextureClientTest, BufferGeometryDefaultSizeSetFormat) { ANativeWindowBuffer* buf; EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 0, 0, PIXEL_FORMAT_RGB_565)); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf)); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); EXPECT_EQ(1, buf->width); EXPECT_EQ(1, buf->height); EXPECT_EQ(PIXEL_FORMAT_RGB_565, buf->format); - ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf)); + ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1)); } TEST_F(SurfaceTextureClientTest, BufferGeometrySetSizeDefaultFormat) { ANativeWindowBuffer* buf; EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 16, 8, 0)); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf)); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); EXPECT_EQ(16, buf->width); EXPECT_EQ(8, buf->height); EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format); - ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf)); + ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1)); } TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeUnset) { ANativeWindowBuffer* buf; EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 16, 8, 0)); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf)); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); EXPECT_EQ(16, buf->width); EXPECT_EQ(8, buf->height); EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format); - ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf)); + ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1)); EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 0, 0, 0)); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf)); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); EXPECT_EQ(1, buf->width); EXPECT_EQ(1, buf->height); EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format); - ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf)); + ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1)); } TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeChangedWithoutFormat) { ANativeWindowBuffer* buf; EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 0, 0, PIXEL_FORMAT_RGB_565)); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf)); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); EXPECT_EQ(1, buf->width); EXPECT_EQ(1, buf->height); EXPECT_EQ(PIXEL_FORMAT_RGB_565, buf->format); - ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf)); + ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1)); EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 16, 8, 0)); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf)); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); EXPECT_EQ(16, buf->width); EXPECT_EQ(8, buf->height); EXPECT_EQ(PIXEL_FORMAT_RGB_565, buf->format); - ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf)); + ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1)); } TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSize) { sp<SurfaceTexture> st(mST); ANativeWindowBuffer* buf; EXPECT_EQ(OK, st->setDefaultBufferSize(16, 8)); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf)); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); EXPECT_EQ(16, buf->width); EXPECT_EQ(8, buf->height); EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format); - ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf)); + ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1)); } TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeAfterDequeue) { ANativeWindowBuffer* buf[2]; ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0])); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1])); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); EXPECT_NE(buf[0], buf[1]); - ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0])); - ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1])); + ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0], -1)); + ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1], -1)); EXPECT_EQ(OK, mST->setDefaultBufferSize(16, 8)); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0])); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1])); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); EXPECT_NE(buf[0], buf[1]); EXPECT_EQ(16, buf[0]->width); EXPECT_EQ(16, buf[1]->width); EXPECT_EQ(8, buf[0]->height); EXPECT_EQ(8, buf[1]->height); - ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0])); - ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1])); + ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0], -1)); + ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1], -1)); } TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeVsGeometry) { ANativeWindowBuffer* buf[2]; ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); EXPECT_EQ(OK, mST->setDefaultBufferSize(16, 8)); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0])); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1])); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); EXPECT_NE(buf[0], buf[1]); EXPECT_EQ(16, buf[0]->width); EXPECT_EQ(16, buf[1]->width); EXPECT_EQ(8, buf[0]->height); EXPECT_EQ(8, buf[1]->height); - ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0])); - ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1])); + ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0], -1)); + ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1], -1)); EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 12, 24, 0)); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0])); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1])); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); EXPECT_NE(buf[0], buf[1]); EXPECT_EQ(12, buf[0]->width); EXPECT_EQ(12, buf[1]->width); EXPECT_EQ(24, buf[0]->height); EXPECT_EQ(24, buf[1]->height); - ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0])); - ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1])); + ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0], -1)); + ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1], -1)); } TEST_F(SurfaceTextureClientTest, SurfaceTextureTooManyUpdateTexImage) { @@ -310,18 +310,18 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureTooManyUpdateTexImage) { ASSERT_EQ(OK, mST->setSynchronousMode(false)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0])); - ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0])); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); + ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1)); EXPECT_EQ(OK, mST->updateTexImage()); EXPECT_EQ(OK, mST->updateTexImage()); ASSERT_EQ(OK, mST->setSynchronousMode(true)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3)); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0])); - ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0])); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1])); - ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1])); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); + ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1)); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); + ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1], -1)); EXPECT_EQ(OK, mST->updateTexImage()); EXPECT_EQ(OK, mST->updateTexImage()); @@ -332,15 +332,15 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeSlowRetire) { android_native_buffer_t* buf[3]; ASSERT_EQ(OK, mST->setSynchronousMode(true)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0])); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1])); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[2])); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[2])); EXPECT_NE(buf[0], buf[1]); EXPECT_NE(buf[1], buf[2]); EXPECT_NE(buf[2], buf[0]); - ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0])); - ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1])); - ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2])); + ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1)); + ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1], -1)); + ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2], -1)); EXPECT_EQ(OK, mST->updateTexImage()); EXPECT_EQ(mST->getCurrentBuffer().get(), buf[0]); EXPECT_EQ(OK, mST->updateTexImage()); @@ -353,19 +353,19 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeFastRetire) { android_native_buffer_t* buf[3]; ASSERT_EQ(OK, mST->setSynchronousMode(true)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0])); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1])); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[2])); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[2])); EXPECT_NE(buf[0], buf[1]); EXPECT_NE(buf[1], buf[2]); EXPECT_NE(buf[2], buf[0]); - ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0])); + ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1)); EXPECT_EQ(OK, mST->updateTexImage()); EXPECT_EQ(mST->getCurrentBuffer().get(), buf[0]); - ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1])); + ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1], -1)); EXPECT_EQ(OK, mST->updateTexImage()); EXPECT_EQ(mST->getCurrentBuffer().get(), buf[1]); - ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2])); + ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2], -1)); EXPECT_EQ(OK, mST->updateTexImage()); EXPECT_EQ(mST->getCurrentBuffer().get(), buf[2]); } @@ -375,20 +375,20 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeDQQR) { ASSERT_EQ(OK, mST->setSynchronousMode(true)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3)); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0])); - ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0])); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); + ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1)); EXPECT_EQ(OK, mST->updateTexImage()); EXPECT_EQ(mST->getCurrentBuffer().get(), buf[0]); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1])); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); EXPECT_NE(buf[0], buf[1]); - ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1])); + ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1], -1)); EXPECT_EQ(OK, mST->updateTexImage()); EXPECT_EQ(mST->getCurrentBuffer().get(), buf[1]); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[2])); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[2])); EXPECT_NE(buf[1], buf[2]); - ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2])); + ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2], -1)); EXPECT_EQ(OK, mST->updateTexImage()); EXPECT_EQ(mST->getCurrentBuffer().get(), buf[2]); } @@ -400,16 +400,16 @@ TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeDequeueCurrent) android_native_buffer_t* firstBuf; ASSERT_EQ(OK, mST->setSynchronousMode(true)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3)); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &firstBuf)); - ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), firstBuf)); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &firstBuf)); + ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), firstBuf, -1)); EXPECT_EQ(OK, mST->updateTexImage()); EXPECT_EQ(mST->getCurrentBuffer().get(), firstBuf); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0])); - ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0])); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1])); - ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1])); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[2])); - ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2])); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); + ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1)); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); + ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1], -1)); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[2])); + ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2], -1)); EXPECT_NE(buf[0], buf[1]); EXPECT_NE(buf[1], buf[2]); EXPECT_NE(buf[2], buf[0]); @@ -422,24 +422,24 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeMinUndequeued) { ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3)); // We should be able to dequeue all the buffers before we've queued mANWy. - EXPECT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0])); - EXPECT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1])); - EXPECT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[2])); + EXPECT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); + EXPECT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); + EXPECT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[2])); - ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[2])); - ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1])); + ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[2], -1)); + ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1], -1)); EXPECT_EQ(OK, mST->updateTexImage()); EXPECT_EQ(mST->getCurrentBuffer().get(), buf[1]); - EXPECT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[2])); + EXPECT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[2])); // Once we've queued a buffer, however we should not be able to dequeue more // than (buffer-count - MIN_UNDEQUEUED_BUFFERS), which is 2 in this case. - EXPECT_EQ(-EBUSY, mANW->dequeueBuffer(mANW.get(), &buf[1])); + EXPECT_EQ(-EBUSY, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); - ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0])); - ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[2])); + ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0], -1)); + ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[2], -1)); } TEST_F(SurfaceTextureClientTest, SetCropCropsCrop) { @@ -449,8 +449,8 @@ TEST_F(SurfaceTextureClientTest, SetCropCropsCrop) { ASSERT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 4, 4)); android_native_buffer_t* buf; - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf)); - ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf)); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); + ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf, -1)); ASSERT_EQ(OK, mST->updateTexImage()); Rect crop = mST->getCurrentCrop(); @@ -500,20 +500,20 @@ TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeWaitRetire) { ASSERT_EQ(OK, mST->setSynchronousMode(true)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3)); // dequeue/queue/update so we have a current buffer - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0])); - ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0])); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); + ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1)); mST->updateTexImage(); MyThread* thread = new MyThread(mST); sp<Thread> threadBase(thread); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0])); - ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0])); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); + ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1)); thread->run(); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1])); - ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1])); - //ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[2])); - //ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2])); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); + ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1], -1)); + //ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[2])); + //ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2], -1)); thread->bufferDequeued(); thread->requestExitAndWait(); } @@ -522,8 +522,8 @@ TEST_F(SurfaceTextureClientTest, GetTransformMatrixReturnsVerticalFlip) { android_native_buffer_t* buf[3]; float mtx[16] = {}; ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0])); - ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0])); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); + ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1)); ASSERT_EQ(OK, mST->updateTexImage()); mST->getTransformMatrix(mtx); @@ -552,8 +552,8 @@ TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffers) android_native_buffer_t* buf[3]; float mtx[16] = {}; ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0])); - ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0])); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); + ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1)); ASSERT_EQ(OK, mST->updateTexImage()); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 6)); // frees buffers mST->getTransformMatrix(mtx); @@ -590,9 +590,9 @@ TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffersWi ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); ASSERT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 8, 8, 0)); - ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0])); + ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, native_window_set_crop(mANW.get(), &crop)); - ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0])); + ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1)); ASSERT_EQ(OK, mST->updateTexImage()); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 6)); // frees buffers mST->getTransformMatrix(mtx); diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp index 078c17b..0060cf7 100644 --- a/libs/gui/tests/SurfaceTexture_test.cpp +++ b/libs/gui/tests/SurfaceTexture_test.cpp @@ -672,18 +672,19 @@ void fillRGBA8BufferSolid(uint8_t* buf, int w, int h, int stride, uint8_t r, // Calls to this function should be wrapped in an ASSERT_NO_FATAL_FAILURE(). void produceOneRGBA8Frame(const sp<ANativeWindow>& anw) { android_native_buffer_t* anb; - ASSERT_EQ(NO_ERROR, anw->dequeueBuffer(anw.get(), &anb)); + ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(anw.get(), + &anb)); ASSERT_TRUE(anb != NULL); sp<GraphicBuffer> buf(new GraphicBuffer(anb, false)); - ASSERT_EQ(NO_ERROR, anw->lockBuffer(anw.get(), buf->getNativeBuffer())); uint8_t* img = NULL; ASSERT_EQ(NO_ERROR, buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img))); fillRGBA8Buffer(img, buf->getWidth(), buf->getHeight(), buf->getStride()); ASSERT_EQ(NO_ERROR, buf->unlock()); - ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf->getNativeBuffer())); + ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf->getNativeBuffer(), + -1)); } TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferNpot) { @@ -696,18 +697,19 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferNpot) { GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN)); ANativeWindowBuffer* anb; - ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb)); + ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), + &anb)); ASSERT_TRUE(anb != NULL); sp<GraphicBuffer> buf(new GraphicBuffer(anb, false)); - ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer())); // Fill the buffer with the a checkerboard pattern uint8_t* img = NULL; buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); fillYV12Buffer(img, texWidth, texHeight, buf->getStride()); buf->unlock(); - ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer())); + ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(), + -1)); mST->updateTexImage(); @@ -741,18 +743,19 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferPow2) { GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN)); ANativeWindowBuffer* anb; - ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb)); + ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), + &anb)); ASSERT_TRUE(anb != NULL); sp<GraphicBuffer> buf(new GraphicBuffer(anb, false)); - ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer())); // Fill the buffer with the a checkerboard pattern uint8_t* img = NULL; buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); fillYV12Buffer(img, texWidth, texHeight, buf->getStride()); buf->unlock(); - ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer())); + ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(), + -1)); mST->updateTexImage(); @@ -801,19 +804,18 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferWithCrop) { ASSERT_EQ(NO_ERROR, native_window_set_crop(mANW.get(), &crop)); ANativeWindowBuffer* anb; - ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb)); + ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), + &anb)); ASSERT_TRUE(anb != NULL); sp<GraphicBuffer> buf(new GraphicBuffer(anb, false)); - ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), - buf->getNativeBuffer())); uint8_t* img = NULL; buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); fillYV12BufferRect(img, texWidth, texHeight, buf->getStride(), crop); buf->unlock(); ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), - buf->getNativeBuffer())); + buf->getNativeBuffer(), -1)); mST->updateTexImage(); @@ -877,7 +879,8 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BuffersRepeatedly) { virtual bool threadLoop() { for (int i = 0; i < numFrames; i++) { ANativeWindowBuffer* anb; - if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) { + if (native_window_dequeue_buffer_and_wait(mANW.get(), + &anb) != NO_ERROR) { return false; } if (anb == NULL) { @@ -885,10 +888,6 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BuffersRepeatedly) { } sp<GraphicBuffer> buf(new GraphicBuffer(anb, false)); - if (mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()) - != NO_ERROR) { - return false; - } const int yuvTexOffsetY = 0; int stride = buf->getStride(); @@ -932,7 +931,7 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BuffersRepeatedly) { } buf->unlock(); - if (mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()) + if (mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(), -1) != NO_ERROR) { return false; } @@ -1093,13 +1092,14 @@ TEST_F(SurfaceTextureGLTest, DisconnectStressTest) { for (int numFrames =0 ; numFrames < 2; numFrames ++) { - if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) { + if (native_window_dequeue_buffer_and_wait(mANW.get(), + &anb) != NO_ERROR) { return false; } if (anb == NULL) { return false; } - if (mANW->queueBuffer(mANW.get(), anb) + if (mANW->queueBuffer(mANW.get(), anb, -1) != NO_ERROR) { return false; } @@ -1147,11 +1147,11 @@ TEST_F(SurfaceTextureGLTest, DisconnectClearsCurrentTexture) { ANativeWindowBuffer *anb; - EXPECT_EQ (OK, mANW->dequeueBuffer(mANW.get(), &anb)); - EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb)); + EXPECT_EQ (OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb)); + EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1)); - EXPECT_EQ (OK, mANW->dequeueBuffer(mANW.get(), &anb)); - EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb)); + EXPECT_EQ (OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb)); + EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1)); EXPECT_EQ(OK,mST->updateTexImage()); EXPECT_EQ(OK,mST->updateTexImage()); @@ -1163,8 +1163,8 @@ TEST_F(SurfaceTextureGLTest, DisconnectClearsCurrentTexture) { ASSERT_EQ(OK, mST->setSynchronousMode(true)); - EXPECT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &anb)); - EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb)); + EXPECT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb)); + EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1)); // Will fail here if mCurrentTexture is not cleared properly mFW->waitForFrame(); @@ -1193,8 +1193,8 @@ TEST_F(SurfaceTextureGLTest, ScaleToWindowMode) { android_native_rect_t odd = {23, 78, 123, 477}; ASSERT_EQ(OK, native_window_set_crop(mANW.get(), &odd)); - EXPECT_EQ (OK, mANW->dequeueBuffer(mANW.get(), &anb)); - EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb)); + EXPECT_EQ (OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb)); + EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1)); mFW->waitForFrame(); EXPECT_EQ(OK,mST->updateTexImage()); Rect r = mST->getCurrentCrop(); @@ -1227,8 +1227,8 @@ TEST_F(SurfaceTextureGLTest, CroppedScalingMode) { // The crop is in the shape of (320, 180) === 16 x 9 android_native_rect_t standard = {10, 20, 330, 200}; ASSERT_EQ(OK, native_window_set_crop(mANW.get(), &standard)); - EXPECT_EQ (OK, mANW->dequeueBuffer(mANW.get(), &anb)); - EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb)); + EXPECT_EQ (OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb)); + EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1)); mFW->waitForFrame(); EXPECT_EQ(OK,mST->updateTexImage()); Rect r = mST->getCurrentCrop(); @@ -1238,8 +1238,8 @@ TEST_F(SurfaceTextureGLTest, CroppedScalingMode) { // make this wider then desired aspect 239 x 100 (2.39:1) android_native_rect_t wide = {20, 30, 259, 130}; ASSERT_EQ(OK, native_window_set_crop(mANW.get(), &wide)); - EXPECT_EQ (OK, mANW->dequeueBuffer(mANW.get(), &anb)); - EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb)); + EXPECT_EQ (OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb)); + EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1)); mFW->waitForFrame(); EXPECT_EQ(OK,mST->updateTexImage()); r = mST->getCurrentCrop(); @@ -1250,8 +1250,8 @@ TEST_F(SurfaceTextureGLTest, CroppedScalingMode) { // This image is taller then desired aspect 400 x 300 (4:3) android_native_rect_t narrow = {0, 0, 400, 300}; ASSERT_EQ(OK, native_window_set_crop(mANW.get(), &narrow)); - EXPECT_EQ (OK, mANW->dequeueBuffer(mANW.get(), &anb)); - EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb)); + EXPECT_EQ (OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb)); + EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1)); mFW->waitForFrame(); EXPECT_EQ(OK,mST->updateTexImage()); r = mST->getCurrentCrop(); @@ -1278,31 +1278,34 @@ TEST_F(SurfaceTextureGLTest, AbandonUnblocksDequeueBuffer) { ANativeWindowBuffer* anb; // Frame 1 - if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) { + if (native_window_dequeue_buffer_and_wait(mANW.get(), + &anb) != NO_ERROR) { return false; } if (anb == NULL) { return false; } - if (mANW->queueBuffer(mANW.get(), anb) + if (mANW->queueBuffer(mANW.get(), anb, -1) != NO_ERROR) { return false; } // Frame 2 - if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) { + if (native_window_dequeue_buffer_and_wait(mANW.get(), + &anb) != NO_ERROR) { return false; } if (anb == NULL) { return false; } - if (mANW->queueBuffer(mANW.get(), anb) + if (mANW->queueBuffer(mANW.get(), anb, -1) != NO_ERROR) { return false; } // Frame 3 - error expected - mDequeueError = mANW->dequeueBuffer(mANW.get(), &anb); + mDequeueError = native_window_dequeue_buffer_and_wait(mANW.get(), + &anb); return false; } @@ -1346,26 +1349,29 @@ TEST_F(SurfaceTextureGLTest, InvalidWidthOrHeightFails) { // make sure it works with small textures mST->setDefaultBufferSize(16, texHeight); - EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb)); + EXPECT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), + &anb)); EXPECT_EQ(16, anb->width); EXPECT_EQ(texHeight, anb->height); - EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb)); + EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb, -1)); EXPECT_EQ(NO_ERROR, mST->updateTexImage()); // make sure it works with GL_MAX_TEXTURE_SIZE mST->setDefaultBufferSize(maxTextureSize, texHeight); - EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb)); + EXPECT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), + &anb)); EXPECT_EQ(maxTextureSize, anb->width); EXPECT_EQ(texHeight, anb->height); - EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb)); + EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb, -1)); EXPECT_EQ(NO_ERROR, mST->updateTexImage()); // make sure it fails with GL_MAX_TEXTURE_SIZE+1 mST->setDefaultBufferSize(maxTextureSize+1, texHeight); - EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb)); + EXPECT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), + &anb)); EXPECT_EQ(maxTextureSize+1, anb->width); EXPECT_EQ(texHeight, anb->height); - EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb)); + EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb, -1)); ASSERT_NE(NO_ERROR, mST->updateTexImage()); } @@ -2134,11 +2140,11 @@ TEST_F(SurfaceTextureFBOTest, BlitFromCpuFilledBufferToFbo) { GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN)); android_native_buffer_t* anb; - ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb)); + ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), + &anb)); ASSERT_TRUE(anb != NULL); sp<GraphicBuffer> buf(new GraphicBuffer(anb, false)); - ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer())); // Fill the buffer with green uint8_t* img = NULL; @@ -2146,7 +2152,8 @@ TEST_F(SurfaceTextureFBOTest, BlitFromCpuFilledBufferToFbo) { fillRGBA8BufferSolid(img, texWidth, texHeight, buf->getStride(), 0, 255, 0, 255); buf->unlock(); - ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer())); + ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(), + -1)); ASSERT_EQ(NO_ERROR, mST->updateTexImage()); @@ -2157,12 +2164,11 @@ TEST_F(SurfaceTextureFBOTest, BlitFromCpuFilledBufferToFbo) { for (int i = 0; i < 4; i++) { SCOPED_TRACE(String8::format("frame %d", i).string()); - ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb)); + ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), + &anb)); ASSERT_TRUE(anb != NULL); buf = new GraphicBuffer(anb, false); - ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), - buf->getNativeBuffer())); // Fill the buffer with red ASSERT_EQ(NO_ERROR, buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, @@ -2171,7 +2177,7 @@ TEST_F(SurfaceTextureFBOTest, BlitFromCpuFilledBufferToFbo) { 0, 255); ASSERT_EQ(NO_ERROR, buf->unlock()); ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), - buf->getNativeBuffer())); + buf->getNativeBuffer(), -1)); ASSERT_EQ(NO_ERROR, mST->updateTexImage()); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index b585d68..5046bf5 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -97,22 +97,23 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) { ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(anw.get(), 3)); ANativeWindowBuffer* buf = 0; - status_t err = anw->dequeueBuffer(anw.get(), &buf); + status_t err = native_window_dequeue_buffer_and_wait(anw.get(), &buf); if (err) { // we could fail if GRALLOC_USAGE_PROTECTED is not supported. // that's okay as long as this is the reason for the failure. // try again without the GRALLOC_USAGE_PROTECTED bit. ASSERT_EQ(NO_ERROR, native_window_set_usage(anw.get(), 0)); - ASSERT_EQ(NO_ERROR, anw->dequeueBuffer(anw.get(), &buf)); + ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(anw.get(), + &buf)); return; } - ASSERT_EQ(NO_ERROR, anw->cancelBuffer(anw.get(), buf)); + ASSERT_EQ(NO_ERROR, anw->cancelBuffer(anw.get(), buf, -1)); for (int i = 0; i < 4; i++) { // Loop to make sure SurfaceFlinger has retired a protected buffer. - ASSERT_EQ(NO_ERROR, anw->dequeueBuffer(anw.get(), &buf)); - ASSERT_EQ(NO_ERROR, anw->lockBuffer(anw.get(), buf)); - ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf)); + ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(anw.get(), + &buf)); + ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf, -1)); } heap = 0; w = h = fmt = 0; diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk index 5aff7a4..80c28a1 100644 --- a/libs/ui/Android.mk +++ b/libs/ui/Android.mk @@ -16,6 +16,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ + Fence.cpp \ FramebufferNativeWindow.cpp \ GraphicBuffer.cpp \ GraphicBufferAllocator.cpp \ @@ -26,8 +27,9 @@ LOCAL_SRC_FILES:= \ LOCAL_SHARED_LIBRARIES := \ libcutils \ - libutils \ - libhardware + libhardware \ + libsync \ + libutils ifneq ($(BOARD_FRAMEBUFFER_FORCE_FORMAT),) LOCAL_CFLAGS += -DFRAMEBUFFER_FORCE_FORMAT=$(BOARD_FRAMEBUFFER_FORCE_FORMAT) diff --git a/libs/ui/Fence.cpp b/libs/ui/Fence.cpp new file mode 100644 index 0000000..cec5876 --- /dev/null +++ b/libs/ui/Fence.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "Fence" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS +//#define LOG_NDEBUG 0 + +#include <sync/sync.h> +#include <ui/Fence.h> +#include <unistd.h> +#include <utils/Log.h> +#include <utils/Trace.h> + +namespace android { + +const sp<Fence> Fence::NO_FENCE = sp<Fence>(); + +Fence::Fence() : + mFenceFd(-1) { +} + +Fence::Fence(int fenceFd) : + mFenceFd(fenceFd) { +} + +Fence::~Fence() { + if (mFenceFd != -1) { + close(mFenceFd); + } +} + +int Fence::wait(unsigned int timeout) { + ATRACE_CALL(); + if (mFenceFd == -1) { + return NO_ERROR; + } + return sync_wait(mFenceFd, timeout); +} + +sp<Fence> Fence::merge(const String8& name, const sp<Fence>& f1, + const sp<Fence>& f2) { + ATRACE_CALL(); + int result = sync_merge(name.string(), f1->mFenceFd, f2->mFenceFd); + if (result == -1) { + status_t err = -errno; + ALOGE("merge: sync_merge(\"%s\", %d, %d) returned an error: %s (%d)", + name.string(), f1->mFenceFd, f2->mFenceFd, + strerror(-err), err); + return NO_FENCE; + } + return sp<Fence>(new Fence(result)); +} + +int Fence::dup() const { + if (mFenceFd == -1) { + return -1; + } + return ::dup(mFenceFd); +} + +size_t Fence::getFlattenedSize() const { + return 0; +} + +size_t Fence::getFdCount() const { + return 1; +} + +status_t Fence::flatten(void* buffer, size_t size, int fds[], + size_t count) const { + if (size != 0 || count != 1) { + return BAD_VALUE; + } + + fds[0] = mFenceFd; + return NO_ERROR; +} + +status_t Fence::unflatten(void const* buffer, size_t size, int fds[], + size_t count) { + if (size != 0 || count != 1) { + return BAD_VALUE; + } + if (mFenceFd != -1) { + // Don't unflatten if we already have a valid fd. + return INVALID_OPERATION; + } + + mFenceFd = fds[0]; + return NO_ERROR; +} + +} // namespace android diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp index dec99b6..31a69b2 100644 --- a/libs/ui/FramebufferNativeWindow.cpp +++ b/libs/ui/FramebufferNativeWindow.cpp @@ -28,6 +28,7 @@ #include <utils/RefBase.h> #include <ui/ANativeObjectBase.h> +#include <ui/Fence.h> #include <ui/FramebufferNativeWindow.h> #include <ui/Rect.h> @@ -92,8 +93,13 @@ FramebufferNativeWindow::FramebufferNativeWindow() mUpdateOnDemand = (fbDev->setUpdateRect != 0); // initialize the buffer FIFO - mNumBuffers = NUM_FRAME_BUFFERS; - mNumFreeBuffers = NUM_FRAME_BUFFERS; + if(fbDev->numFramebuffers >= MIN_NUM_FRAME_BUFFERS && + fbDev->numFramebuffers <= MAX_NUM_FRAME_BUFFERS){ + mNumBuffers = fbDev->numFramebuffers; + } else { + mNumBuffers = MIN_NUM_FRAME_BUFFERS; + } + mNumFreeBuffers = mNumBuffers; mBufferHead = mNumBuffers-1; /* @@ -145,19 +151,23 @@ FramebufferNativeWindow::FramebufferNativeWindow() ANativeWindow::setSwapInterval = setSwapInterval; ANativeWindow::dequeueBuffer = dequeueBuffer; - ANativeWindow::lockBuffer = lockBuffer; ANativeWindow::queueBuffer = queueBuffer; ANativeWindow::query = query; ANativeWindow::perform = perform; + + ANativeWindow::dequeueBuffer_DEPRECATED = dequeueBuffer_DEPRECATED; + ANativeWindow::lockBuffer_DEPRECATED = lockBuffer_DEPRECATED; + ANativeWindow::queueBuffer_DEPRECATED = queueBuffer_DEPRECATED; } FramebufferNativeWindow::~FramebufferNativeWindow() { if (grDev) { - if (buffers[0] != NULL) - grDev->free(grDev, buffers[0]->handle); - if (buffers[1] != NULL) - grDev->free(grDev, buffers[1]->handle); + for(int i = 0; i < mNumBuffers; i++) { + if (buffers[i] != NULL) { + grDev->free(grDev, buffers[i]->handle); + } + } gralloc_close(grDev); } @@ -207,9 +217,24 @@ int FramebufferNativeWindow::getCurrentBufferIndex() const return index; } -int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window, +int FramebufferNativeWindow::dequeueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer** buffer) { + int fenceFd = -1; + int result = dequeueBuffer(window, buffer, &fenceFd); + sp<Fence> fence(new Fence(fenceFd)); + int waitResult = fence->wait(Fence::TIMEOUT_NEVER); + if (waitResult != OK) { + ALOGE("dequeueBuffer_DEPRECATED: Fence::wait returned an " + "error: %d", waitResult); + return waitResult; + } + return result; +} + +int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window, + ANativeWindowBuffer** buffer, int* fenceFd) +{ FramebufferNativeWindow* self = getSelf(window); Mutex::Autolock _l(self->mutex); framebuffer_device_t* fb = self->fbDev; @@ -218,43 +243,45 @@ int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window, if (self->mBufferHead >= self->mNumBuffers) self->mBufferHead = 0; - // wait for a free buffer - while (!self->mNumFreeBuffers) { + // wait for a free non-front buffer + while (self->mNumFreeBuffers < 2) { self->mCondition.wait(self->mutex); } + ALOG_ASSERT(self->buffers[index] != self->front); + // get this buffer self->mNumFreeBuffers--; self->mCurrentBufferIndex = index; *buffer = self->buffers[index].get(); + *fenceFd = -1; return 0; } -int FramebufferNativeWindow::lockBuffer(ANativeWindow* window, +int FramebufferNativeWindow::lockBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer) { - FramebufferNativeWindow* self = getSelf(window); - Mutex::Autolock _l(self->mutex); - - const int index = self->mCurrentBufferIndex; - - // wait that the buffer we're locking is not front anymore - while (self->front == buffer) { - self->mCondition.wait(self->mutex); - } - return NO_ERROR; } -int FramebufferNativeWindow::queueBuffer(ANativeWindow* window, +int FramebufferNativeWindow::queueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer) { + return queueBuffer(window, buffer, -1); +} + +int FramebufferNativeWindow::queueBuffer(ANativeWindow* window, + ANativeWindowBuffer* buffer, int fenceFd) +{ FramebufferNativeWindow* self = getSelf(window); Mutex::Autolock _l(self->mutex); framebuffer_device_t* fb = self->fbDev; buffer_handle_t handle = static_cast<NativeBuffer*>(buffer)->handle; + sp<Fence> fence(new Fence(fenceFd)); + fence->wait(Fence::TIMEOUT_NEVER); + const int index = self->mCurrentBufferIndex; int res = fb->post(fb, handle); self->front = static_cast<NativeBuffer*>(buffer); diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp index 2c7cdf0..a3d8b01 100644 --- a/libs/ui/Region.cpp +++ b/libs/ui/Region.cpp @@ -66,12 +66,6 @@ Region::Region(const Rect& rhs) { } -Region::Region(const void* buffer) -{ - status_t err = read(buffer); - ALOGE_IF(err<0, "error %s reading Region from buffer", strerror(err)); -} - Region::~Region() { } @@ -561,55 +555,33 @@ void Region::translate(Region& dst, const Region& reg, int dx, int dy) // ---------------------------------------------------------------------------- -ssize_t Region::write(void* buffer, size_t size) const -{ -#if VALIDATE_REGIONS - validate(*this, "write(buffer)"); -#endif - const size_t count = mStorage.size(); - const size_t sizeNeeded = sizeof(int32_t) + (1+count)*sizeof(Rect); - if (buffer != NULL) { - if (sizeNeeded > size) return NO_MEMORY; - int32_t* const p = static_cast<int32_t*>(buffer); - *p = count; - memcpy(p+1, &mBounds, sizeof(Rect)); - if (count) { - memcpy(p+5, mStorage.array(), count*sizeof(Rect)); - } - } - return ssize_t(sizeNeeded); +size_t Region::getSize() const { + return (mStorage.size() + 1) * sizeof(Rect); } -ssize_t Region::read(const void* buffer) -{ - int32_t const* const p = static_cast<int32_t const*>(buffer); - const size_t count = *p; - memcpy(&mBounds, p+1, sizeof(Rect)); - mStorage.clear(); - if (count) { - mStorage.insertAt(0, count); - memcpy(mStorage.editArray(), p+5, count*sizeof(Rect)); - } -#if VALIDATE_REGIONS - validate(*this, "read(buffer)"); -#endif - return ssize_t(sizeof(int32_t) + (1+count)*sizeof(Rect)); -} - -ssize_t Region::writeEmpty(void* buffer, size_t size) -{ - const size_t sizeNeeded = sizeof(int32_t) + sizeof(Rect); - if (sizeNeeded > size) return NO_MEMORY; - int32_t* const p = static_cast<int32_t*>(buffer); - memset(p, 0, sizeNeeded); - return ssize_t(sizeNeeded); +status_t Region::flatten(void* buffer) const { + Rect* rects = reinterpret_cast<Rect*>(buffer); + *rects++ = mBounds; + memcpy(rects, mStorage.array(), mStorage.size() * sizeof(Rect)); + return NO_ERROR; } -bool Region::isEmpty(void* buffer) -{ - int32_t const* const p = static_cast<int32_t const*>(buffer); - Rect const* const b = reinterpret_cast<Rect const *>(p+1); - return b->isEmpty(); +status_t Region::unflatten(void const* buffer, size_t size) { + mStorage.clear(); + if (size >= sizeof(Rect)) { + Rect const* rects = reinterpret_cast<Rect const*>(buffer); + mBounds = *rects++; + size -= sizeof(Rect); + size_t count = size / sizeof(Rect); + if (count > 0) { + ssize_t err = mStorage.insertAt(0, count); + if (err < 0) { + return status_t(err); + } + memcpy(mStorage.editArray(), rects, count*sizeof(Rect)); + } + } + return NO_ERROR; } // ---------------------------------------------------------------------------- diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk index ddfb83e..c9f8fd4 100644 --- a/libs/utils/Android.mk +++ b/libs/utils/Android.mk @@ -26,6 +26,7 @@ commonSources:= \ FileMap.cpp \ Flattenable.cpp \ LinearTransform.cpp \ + Log.cpp \ PropertyMap.cpp \ RefBase.cpp \ SharedBuffer.cpp \ diff --git a/libs/utils/LinearTransform.cpp b/libs/utils/LinearTransform.cpp index d752415..b7d28d4 100644 --- a/libs/utils/LinearTransform.cpp +++ b/libs/utils/LinearTransform.cpp @@ -114,6 +114,7 @@ static bool linear_transform_s64_to_s64( int64_t basis1, int32_t N, uint32_t D, + bool invert_frac, int64_t basis2, int64_t* out) { uint64_t scaled, res; @@ -137,8 +138,8 @@ static bool linear_transform_s64_to_s64( is_neg = !is_neg; if (!scale_u64_to_u64(abs_val, - ABS(N), - D, + invert_frac ? D : ABS(N), + invert_frac ? ABS(N) : D, &scaled, is_neg)) return false; // overflow/undeflow @@ -191,6 +192,7 @@ bool LinearTransform::doForwardTransform(int64_t a_in, int64_t* b_out) const { a_zero, a_to_b_numer, a_to_b_denom, + false, b_zero, b_out); } @@ -201,8 +203,9 @@ bool LinearTransform::doReverseTransform(int64_t b_in, int64_t* a_out) const { return linear_transform_s64_to_s64(b_in, b_zero, - a_to_b_denom, a_to_b_numer, + a_to_b_denom, + true, a_zero, a_out); } diff --git a/libs/utils/Log.cpp b/libs/utils/Log.cpp new file mode 100644 index 0000000..bffb56e --- /dev/null +++ b/libs/utils/Log.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "Log" + +#include <utils/Log.h> +#include <utils/Timers.h> + +namespace android { + +LogIfSlow::LogIfSlow(const char* tag, android_LogPriority priority, + int timeoutMillis, const char* message) : + mTag(tag), mPriority(priority), mTimeoutMillis(timeoutMillis), mMessage(message), + mStart(systemTime(SYSTEM_TIME_BOOTTIME)) { +} + +LogIfSlow::~LogIfSlow() { + int durationMillis = nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_BOOTTIME) - mStart); + if (durationMillis > mTimeoutMillis) { + LOG_PRI(mPriority, mTag, "%s: %dms", mMessage, durationMillis); + } +} + +} // namespace android diff --git a/libs/utils/SystemClock.cpp b/libs/utils/SystemClock.cpp index 8b8ac10..53e0626 100644 --- a/libs/utils/SystemClock.cpp +++ b/libs/utils/SystemClock.cpp @@ -106,7 +106,22 @@ int64_t uptimeMillis() */ int64_t elapsedRealtime() { + return nanoseconds_to_milliseconds(elapsedRealtimeNano()); +} + +/* + * native public static long elapsedRealtimeNano(); + */ +int64_t elapsedRealtimeNano() +{ #ifdef HAVE_ANDROID_OS + struct timespec ts; + int result = clock_gettime(CLOCK_BOOTTIME, &ts); + if (result == 0) { + return seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec; + } + + // CLOCK_BOOTTIME doesn't exist, fallback to /dev/alarm static int s_fd = -1; if (s_fd == -1) { @@ -114,25 +129,20 @@ int64_t elapsedRealtime() if (android_atomic_cmpxchg(-1, fd, &s_fd)) { close(fd); } + result = ioctl(s_fd, + ANDROID_ALARM_GET_TIME(ANDROID_ALARM_ELAPSED_REALTIME), &ts); } - struct timespec ts; - int result = ioctl(s_fd, - ANDROID_ALARM_GET_TIME(ANDROID_ALARM_ELAPSED_REALTIME), &ts); - if (result == 0) { - int64_t when = seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec; - return (int64_t) nanoseconds_to_milliseconds(when); - } else { - // XXX: there was an error, probably because the driver didn't - // exist ... this should return - // a real error, like an exception! - int64_t when = systemTime(SYSTEM_TIME_MONOTONIC); - return (int64_t) nanoseconds_to_milliseconds(when); + return seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec; } + + // XXX: there was an error, probably because the driver didn't + // exist ... this should return + // a real error, like an exception! + return systemTime(SYSTEM_TIME_MONOTONIC); #else - int64_t when = systemTime(SYSTEM_TIME_MONOTONIC); - return (int64_t) nanoseconds_to_milliseconds(when); + return systemTime(SYSTEM_TIME_MONOTONIC); #endif } diff --git a/libs/utils/Timers.cpp b/libs/utils/Timers.cpp index 64b4701..d4f8516 100644 --- a/libs/utils/Timers.cpp +++ b/libs/utils/Timers.cpp @@ -39,7 +39,8 @@ nsecs_t systemTime(int clock) CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID, - CLOCK_THREAD_CPUTIME_ID + CLOCK_THREAD_CPUTIME_ID, + CLOCK_BOOTTIME }; struct timespec t; t.tv_sec = t.tv_nsec = 0; diff --git a/libs/utils/VectorImpl.cpp b/libs/utils/VectorImpl.cpp index e78faa8..020ec15 100644 --- a/libs/utils/VectorImpl.cpp +++ b/libs/utils/VectorImpl.cpp @@ -20,7 +20,8 @@ #include <stdlib.h> #include <stdio.h> -#include <utils/Log.h> +#include <cutils/log.h> + #include <utils/Errors.h> #include <utils/SharedBuffer.h> #include <utils/VectorImpl.h> @@ -56,9 +57,8 @@ VectorImpl::VectorImpl(const VectorImpl& rhs) VectorImpl::~VectorImpl() { - ALOG_ASSERT(!mCount, - "[%p] " - "subclasses of VectorImpl must call finish_vector()" + ALOGW_IF(mCount, + "[%p] subclasses of VectorImpl must call finish_vector()" " in their destructor. Leaking %d bytes.", this, (int)(mCount*mItemSize)); // We can't call _do_destroy() here because the vtable is already gone. @@ -66,7 +66,7 @@ VectorImpl::~VectorImpl() VectorImpl& VectorImpl::operator = (const VectorImpl& rhs) { - ALOG_ASSERT(mItemSize == rhs.mItemSize, + LOG_ALWAYS_FATAL_IF(mItemSize != rhs.mItemSize, "Vector<> have different types (this=%p, rhs=%p)", this, &rhs); if (this != &rhs) { release_storage(); @@ -251,6 +251,10 @@ ssize_t VectorImpl::replaceAt(const void* prototype, size_t index) ALOG_ASSERT(index<size(), "[%p] replace: index=%d, size=%d", this, (int)index, (int)size()); + if (index >= size()) { + return BAD_INDEX; + } + void* item = editItemLocation(index); if (item != prototype) { if (item == 0) @@ -294,10 +298,13 @@ void* VectorImpl::editItemLocation(size_t index) ALOG_ASSERT(index<capacity(), "[%p] editItemLocation: index=%d, capacity=%d, count=%d", this, (int)index, (int)capacity(), (int)mCount); - - void* buffer = editArrayImpl(); - if (buffer) - return reinterpret_cast<char*>(buffer) + index*mItemSize; + + if (index < capacity()) { + void* buffer = editArrayImpl(); + if (buffer) { + return reinterpret_cast<char*>(buffer) + index*mItemSize; + } + } return 0; } @@ -307,9 +314,12 @@ const void* VectorImpl::itemLocation(size_t index) const "[%p] itemLocation: index=%d, capacity=%d, count=%d", this, (int)index, (int)capacity(), (int)mCount); - const void* buffer = arrayImpl(); - if (buffer) - return reinterpret_cast<const char*>(buffer) + index*mItemSize; + if (index < capacity()) { + const void* buffer = arrayImpl(); + if (buffer) { + return reinterpret_cast<const char*>(buffer) + index*mItemSize; + } + } return 0; } @@ -484,15 +494,6 @@ void VectorImpl::_do_move_backward(void* dest, const void* from, size_t num) con do_move_backward(dest, from, num); } -void VectorImpl::reservedVectorImpl1() { } -void VectorImpl::reservedVectorImpl2() { } -void VectorImpl::reservedVectorImpl3() { } -void VectorImpl::reservedVectorImpl4() { } -void VectorImpl::reservedVectorImpl5() { } -void VectorImpl::reservedVectorImpl6() { } -void VectorImpl::reservedVectorImpl7() { } -void VectorImpl::reservedVectorImpl8() { } - /*****************************************************************************/ SortedVectorImpl::SortedVectorImpl(size_t itemSize, uint32_t flags) @@ -608,16 +609,6 @@ ssize_t SortedVectorImpl::remove(const void* item) return i; } -void SortedVectorImpl::reservedSortedVectorImpl1() { }; -void SortedVectorImpl::reservedSortedVectorImpl2() { }; -void SortedVectorImpl::reservedSortedVectorImpl3() { }; -void SortedVectorImpl::reservedSortedVectorImpl4() { }; -void SortedVectorImpl::reservedSortedVectorImpl5() { }; -void SortedVectorImpl::reservedSortedVectorImpl6() { }; -void SortedVectorImpl::reservedSortedVectorImpl7() { }; -void SortedVectorImpl::reservedSortedVectorImpl8() { }; - - /*****************************************************************************/ }; // namespace android diff --git a/libs/utils/ZipFileRO.cpp b/libs/utils/ZipFileRO.cpp index cad7720..cc62213 100644 --- a/libs/utils/ZipFileRO.cpp +++ b/libs/utils/ZipFileRO.cpp @@ -118,7 +118,7 @@ ZipFileRO::~ZipFileRO() { */ int ZipFileRO::entryToIndex(const ZipEntryRO entry) const { - long ent = ((long) entry) - kZipEntryAdj; + long ent = ((intptr_t) entry) - kZipEntryAdj; if (ent < 0 || ent >= mHashTableSize || mHashTable[ent].name == NULL) { ALOGW("Invalid ZipEntryRO %p (%ld)\n", entry, ent); return -1; @@ -320,6 +320,25 @@ bool ZipFileRO::mapCentralDirectory(void) return true; } + +/* + * Round up to the next highest power of 2. + * + * Found on http://graphics.stanford.edu/~seander/bithacks.html. + */ +static unsigned int roundUpPower2(unsigned int val) +{ + val--; + val |= val >> 1; + val |= val >> 2; + val |= val >> 4; + val |= val >> 8; + val |= val >> 16; + val++; + + return val; +} + bool ZipFileRO::parseZipArchive(void) { bool result = false; @@ -459,7 +478,7 @@ ZipEntryRO ZipFileRO::findEntryByIndex(int idx) const for (int ent = 0; ent < mHashTableSize; ent++) { if (mHashTable[ent].name != NULL) { if (idx-- == 0) - return (ZipEntryRO) (ent + kZipEntryAdj); + return (ZipEntryRO) (intptr_t)(ent + kZipEntryAdj); } } diff --git a/libs/utils/misc.cpp b/libs/utils/misc.cpp index b3c99e6..445a23a 100644 --- a/libs/utils/misc.cpp +++ b/libs/utils/misc.cpp @@ -39,90 +39,6 @@ using namespace android; namespace android { /* - * Like strdup(), but uses C++ "new" operator instead of malloc. - */ -char* strdupNew(const char* str) -{ - char* newStr; - int len; - - if (str == NULL) - return NULL; - - len = strlen(str); - newStr = new char[len+1]; - memcpy(newStr, str, len+1); - - return newStr; -} - -/* - * Concatenate an argument vector. - */ -char* concatArgv(int argc, const char* const argv[]) -{ - char* newStr = NULL; - int len, totalLen, posn, idx; - - /* - * First, figure out the total length. - */ - totalLen = idx = 0; - while (1) { - if (idx == argc || argv[idx] == NULL) - break; - if (idx) - totalLen++; // leave a space between args - totalLen += strlen(argv[idx]); - idx++; - } - - /* - * Alloc the string. - */ - newStr = new char[totalLen +1]; - if (newStr == NULL) - return NULL; - - /* - * Finally, allocate the string and copy data over. - */ - idx = posn = 0; - while (1) { - if (idx == argc || argv[idx] == NULL) - break; - if (idx) - newStr[posn++] = ' '; - - len = strlen(argv[idx]); - memcpy(&newStr[posn], argv[idx], len); - posn += len; - - idx++; - } - - assert(posn == totalLen); - newStr[posn] = '\0'; - - return newStr; -} - -/* - * Count the #of args in an argument vector. Don't count the final NULL. - */ -int countArgv(const char* const argv[]) -{ - int count = 0; - - while (argv[count] != NULL) - count++; - - return count; -} - - -#include <stdio.h> -/* * Get a file's type. */ FileType getFileType(const char* fileName) @@ -172,24 +88,6 @@ time_t getFileModDate(const char* fileName) return sb.st_mtime; } -/* - * Round up to the next highest power of 2. - * - * Found on http://graphics.stanford.edu/~seander/bithacks.html. - */ -unsigned int roundUpPower2(unsigned int val) -{ - val--; - val |= val >> 1; - val |= val >> 2; - val |= val >> 4; - val |= val >> 8; - val |= val >> 16; - val++; - - return val; -} - struct sysprop_change_callback_info { sysprop_change_callback callback; int priority; diff --git a/opengl/libagl/Android.mk b/opengl/libagl/Android.mk index 15e58f2..639c4d7 100644 --- a/opengl/libagl/Android.mk +++ b/opengl/libagl/Android.mk @@ -26,7 +26,7 @@ LOCAL_CFLAGS += -DLOG_TAG=\"libagl\" LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES LOCAL_CFLAGS += -fvisibility=hidden -LOCAL_SHARED_LIBRARIES := libcutils libhardware libutils libpixelflinger libETC1 +LOCAL_SHARED_LIBRARIES := libcutils libhardware libutils libpixelflinger libETC1 libui LOCAL_LDLIBS := -lpthread -ldl ifeq ($(TARGET_ARCH),arm) diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp index c31aebf..172ef95 100644 --- a/opengl/libagl/egl.cpp +++ b/opengl/libagl/egl.cpp @@ -31,6 +31,7 @@ #include <utils/threads.h> #include <ui/ANativeObjectBase.h> +#include <ui/Fence.h> #include <EGL/egl.h> #include <EGL/eglext.h> @@ -372,7 +373,16 @@ EGLBoolean egl_window_surface_v2_t::connect() GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN); // dequeue a buffer - if (nativeWindow->dequeueBuffer(nativeWindow, &buffer) != NO_ERROR) { + int fenceFd = -1; + if (nativeWindow->dequeueBuffer(nativeWindow, &buffer, + &fenceFd) != NO_ERROR) { + return setError(EGL_BAD_ALLOC, EGL_FALSE); + } + + // wait for the buffer + sp<Fence> fence(new Fence(fenceFd)); + if (fence->wait(Fence::TIMEOUT_NEVER) != NO_ERROR) { + nativeWindow->cancelBuffer(nativeWindow, buffer, fenceFd); return setError(EGL_BAD_ALLOC, EGL_FALSE); } @@ -392,8 +402,6 @@ EGLBoolean egl_window_surface_v2_t::connect() // keep a reference on the buffer buffer->common.incRef(&buffer->common); - // Lock the buffer - nativeWindow->lockBuffer(nativeWindow, buffer); // pin the buffer down if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) { @@ -412,7 +420,7 @@ void egl_window_surface_v2_t::disconnect() unlock(buffer); } // enqueue the last frame - nativeWindow->queueBuffer(nativeWindow, buffer); + nativeWindow->queueBuffer(nativeWindow, buffer, -1); if (buffer) { buffer->common.decRef(&buffer->common); buffer = 0; @@ -517,15 +525,17 @@ EGLBoolean egl_window_surface_v2_t::swapBuffers() unlock(buffer); previousBuffer = buffer; - nativeWindow->queueBuffer(nativeWindow, buffer); + nativeWindow->queueBuffer(nativeWindow, buffer, -1); buffer = 0; // dequeue a new buffer - if (nativeWindow->dequeueBuffer(nativeWindow, &buffer) == NO_ERROR) { - - // TODO: lockBuffer should rather be executed when the very first - // direct rendering occurs. - nativeWindow->lockBuffer(nativeWindow, buffer); + int fenceFd = -1; + if (nativeWindow->dequeueBuffer(nativeWindow, &buffer, &fenceFd) == NO_ERROR) { + sp<Fence> fence(new Fence(fenceFd)); + if (fence->wait(Fence::TIMEOUT_NEVER)) { + nativeWindow->cancelBuffer(nativeWindow, buffer, fenceFd); + return setError(EGL_BAD_ALLOC, EGL_FALSE); + } // reallocate the depth-buffer if needed if ((width != buffer->width) || (height != buffer->height)) { diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk index 42aaa24..eea79f8 100644 --- a/opengl/libs/Android.mk +++ b/opengl/libs/Android.mk @@ -122,7 +122,7 @@ LOCAL_SRC_FILES:= \ GLES2/gl2.cpp.arm \ # -LOCAL_SHARED_LIBRARIES += libcutils libEGL +LOCAL_SHARED_LIBRARIES += libcutils libutils libEGL LOCAL_LDLIBS := -lpthread -ldl LOCAL_MODULE:= libGLESv2 diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp index a46aa38..80072ab 100644 --- a/opengl/libs/EGL/egl_display.cpp +++ b/opengl/libs/EGL/egl_display.cpp @@ -263,7 +263,13 @@ EGLBoolean egl_display_t::terminate() { Mutex::Autolock _l(lock); if (refs == 0) { - return setError(EGL_NOT_INITIALIZED, EGL_FALSE); + /* + * From the EGL spec (3.2): + * "Termination of a display that has already been terminated, + * (...), is allowed, but the only effect of such a call is + * to return EGL_TRUE (...) + */ + return EGL_TRUE; } // this is specific to Android, display termination is ref-counted. diff --git a/opengl/libs/GLES2/gl2.cpp b/opengl/libs/GLES2/gl2.cpp index 4345c2b..b00af1b 100644 --- a/opengl/libs/GLES2/gl2.cpp +++ b/opengl/libs/GLES2/gl2.cpp @@ -26,6 +26,9 @@ #include <cutils/log.h> #include <cutils/properties.h> +#define ATRACE_TAG ATRACE_TAG_GRAPHICS +#include <utils/Trace.h> + #include "hooks.h" #include "egl_impl.h" @@ -40,6 +43,7 @@ using namespace android; #undef CALL_GL_API_RETURN #define DEBUG_CALL_GL_API 0 +#define SYSTRACE_CALL_GL_API 0 #if USE_FAST_TLS_KEY @@ -86,6 +90,13 @@ using namespace android; ALOGD("[" #_api "] 0x%x", status); \ } +#elif SYSTRACE_CALL_GL_API + + #define CALL_GL_API(_api, ...) \ + ATRACE_CALL(); \ + gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \ + _c->_api(__VA_ARGS__); + #else #define CALL_GL_API(_api, ...) \ diff --git a/opengl/libs/GLES_trace/src/gltrace_context.cpp b/opengl/libs/GLES_trace/src/gltrace_context.cpp index 45dbb43..3a8decc 100644 --- a/opengl/libs/GLES_trace/src/gltrace_context.cpp +++ b/opengl/libs/GLES_trace/src/gltrace_context.cpp @@ -119,7 +119,7 @@ GLTraceContext *GLTraceState::createTraceContext(int version, EGLContext eglCont const size_t DEFAULT_BUFFER_SIZE = 8192; BufferedOutputStream *stream = new BufferedOutputStream(mStream, DEFAULT_BUFFER_SIZE); - GLTraceContext *traceContext = new GLTraceContext(id, this, stream); + GLTraceContext *traceContext = new GLTraceContext(id, version, this, stream); mPerContextState[eglContext] = traceContext; return traceContext; @@ -129,8 +129,10 @@ GLTraceContext *GLTraceState::getTraceContext(EGLContext c) { return mPerContextState[c]; } -GLTraceContext::GLTraceContext(int id, GLTraceState *state, BufferedOutputStream *stream) : +GLTraceContext::GLTraceContext(int id, int version, GLTraceState *state, + BufferedOutputStream *stream) : mId(id), + mVersion(version), mState(state), mBufferedOutputStream(stream), mElementArrayBuffers(DefaultKeyedVector<GLuint, ElementArrayBuffer*>(NULL)) @@ -143,6 +145,10 @@ int GLTraceContext::getId() { return mId; } +int GLTraceContext::getVersion() { + return mVersion; +} + GLTraceState *GLTraceContext::getGlobalTraceState() { return mState; } @@ -203,6 +209,8 @@ void GLTraceContext::traceGLMessage(GLMessage *msg) { GLMessage_Function func = msg->function(); if (func == GLMessage::eglSwapBuffers + || func == GLMessage::eglCreateContext + || func == GLMessage::eglMakeCurrent || func == GLMessage::glDrawArrays || func == GLMessage::glDrawElements) { mBufferedOutputStream->flush(); diff --git a/opengl/libs/GLES_trace/src/gltrace_context.h b/opengl/libs/GLES_trace/src/gltrace_context.h index 323cfdc..4c38bba 100644 --- a/opengl/libs/GLES_trace/src/gltrace_context.h +++ b/opengl/libs/GLES_trace/src/gltrace_context.h @@ -50,6 +50,7 @@ public: /** GL Trace Context info associated with each EGLContext */ class GLTraceContext { int mId; /* unique context id */ + int mVersion; /* GL version, e.g: egl_connection_t::GLESv2_INDEX */ GLTraceState *mState; /* parent GL Trace state (for per process GL Trace State Info) */ void *fbcontents; /* memory area to read framebuffer contents */ @@ -65,8 +66,9 @@ class GLTraceContext { public: gl_hooks_t *hooks; - GLTraceContext(int id, GLTraceState *state, BufferedOutputStream *stream); + GLTraceContext(int id, int version, GLTraceState *state, BufferedOutputStream *stream); int getId(); + int getVersion(); GLTraceState *getGlobalTraceState(); void getCompressedFB(void **fb, unsigned *fbsize, unsigned *fbwidth, unsigned *fbheight, diff --git a/opengl/libs/GLES_trace/src/gltrace_fixup.cpp b/opengl/libs/GLES_trace/src/gltrace_fixup.cpp index 3597b26..1bd790e 100644 --- a/opengl/libs/GLES_trace/src/gltrace_fixup.cpp +++ b/opengl/libs/GLES_trace/src/gltrace_fixup.cpp @@ -15,6 +15,7 @@ */ #include <cutils/log.h> +#include <EGL/egldefs.h> #include <GLES/gl.h> #include <GLES/glext.h> #include <GLES2/gl2.h> @@ -592,6 +593,11 @@ void trace_VertexAttribPointerData(GLTraceContext *context, } void trace_VertexAttribPointerDataForGlDrawArrays(GLTraceContext *context, GLMessage *glmsg) { + if (context->getVersion() == egl_connection_t::GLESv1_INDEX) { + // only supported for GLES2 and above + return; + } + /* void glDrawArrays(GLenum mode, GLint first, GLsizei count) */ GLsizei count = glmsg->args(2).intvalue(0); @@ -604,6 +610,11 @@ void trace_VertexAttribPointerDataForGlDrawArrays(GLTraceContext *context, GLMes void trace_VertexAttribPointerDataForGlDrawElements(GLTraceContext *context, GLMessage *glmsg, GLvoid *indices) { + if (context->getVersion() == egl_connection_t::GLESv1_INDEX) { + // only supported for GLES2 and above + return; + } + /* void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) */ GLsizei count = glmsg->args(1).intvalue(0); GLenum type = glmsg->args(2).intvalue(0); diff --git a/opengl/specs/EGL_ANDROID_fence_sync.txt b/opengl/specs/EGL_ANDROID_fence_sync.txt new file mode 100644 index 0000000..316ee1c --- /dev/null +++ b/opengl/specs/EGL_ANDROID_fence_sync.txt @@ -0,0 +1,268 @@ +Name + + ANDROID_fence_sync + +Name Strings + + EGL_ANDROID_fence_sync + +Contributors + + Jamie Gennis + +Contact + + Jamie Gennis, Google Inc. (jgennis 'at' google.com) + +Status + + Draft. + +Version + + Version 2, July 23, 2012 + +Number + + EGL Extension #XXX + +Dependencies + + Requires EGL 1.1 + + This extension is written against the wording of the EGL 1.2 Specification + + EGL_KHR_fence_sync is required. + +Overview + + This extension enables the creation of EGL fence sync objects that are + associated with an Android Sync HAL fence object. These EGL fence sync + objects have nearly identical semantics to those defined by the + KHR_fence_sync extension, except that they have an additional attribute + storing the file descriptor referring to the native Android fence object. + +New Types + + None. + +New Procedures and Functions + + EGLint eglDupAndroidFenceFDANDROID( + EGLDisplay dpy, + EGLSyncKHR); + +New Tokens + + Accepted by the <type> parameter of eglCreateSyncKHR, and returned + in <value> when eglGetSyncAttribKHR is called with <attribute> + EGL_SYNC_TYPE_KHR: + + EGL_SYNC_ANDROID_FENCE_ANDROID 0x3144 + + Accepted by the <attrib_list> parameter of eglCreateSyncKHR: + + EGL_SYNC_ANDROID_FENCE_FD_ANDROID 0x3145 + + Accepted by the <attrib_list> parameter of eglCreateSyncKHR, and returned + by eglDupAndroidFenceFDANDROID in the event of an error: + + EGL_NO_ANDROID_FENCE_ANDROID -1 + + Returned in <value> when eglGetSyncAttribKHR is called with <attribute> + EGL_SYNC_CONDITION_KHR: + + EGL_SYNC_ANDROID_FENCE_SIGNALED_ANDROID 0x3146 + +Changes to Chapter 3 of the EGL 1.2 Specification (EGL Functions and Errors) + + Add the following after the sixth paragraph of Section 3.8.1 (Sync + Objects), added by KHR_fence_sync + + "If <type> is EGL_SYNC_ANDROID_FENCE_ANDROID, an EGL Android fence sync + object is created. In this case the EGL_SYNC_ANDROID_FENCE_FD_ANDROID + attribute may optionally be specified. If this attribute is specified, it + must be set to either a file descriptor that refers to a native Android + fence object or to the value EGL_NO_ANDROID_FENCE_ANDROID. + + The default values for the EGL Android fence sync object attributes are as + follows: + + Attribute Name Initial Attribute Value(s) + --------------- -------------------------- + EGL_SYNC_TYPE_KHR EGL_SYNC_ANDROID_FENCE_ANDROID + EGL_SYNC_STATUS_KHR EGL_UNSIGNALED_KHR + EGL_SYNC_CONDITION_KHR EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR + EGL_SYNC_ANDROID_FENCE_FD_ANDROID EGL_NO_ANDROID_FENCE_ANDROID + + If the EGL_SYNC_ANDROID_FENCE_FD_ANDROID attribute is not + EGL_NO_ANDROID_FENCE_ANDROID then the EGL_SYNC_CONDITION_KHR attribute is + set to EGL_SYNC_ANDROID_FENCE_SIGNALED_ANDROID and the EGL_SYNC_STATUS_KHR + attribute is set to reflect the signal status of the native Android fence + object. Additionally, the EGL implementation assumes ownership of the file + descriptor, so the caller must not use it after calling eglCreateSyncKHR." + + Modify Section 3.8.1 (Sync Objects), added by KHR_fence_sync, starting at + the seventh paragraph + + "When a fence sync object is created or when an EGL Android fence sync + object is created with the EGL_SYNC_ANDROID_FENCE_FD_ANDROID attribute set + to EGL_NO_ANDROID_FENCE_ANDROID, eglCreateSyncKHR also inserts a fence + command into the command stream of the bound client API's current context + (i.e., the context returned by eglGetCurrentContext), and associates it + with the newly created sync object. + + After associating the fence command with an EGL Android fence sync object, + the next Flush() operation performed by the current client API causes a + new native Android fence object to be created, and the + EGL_SYNC_ANDROID_FENCE_ANDROID attribute of the EGL Android fence object + is set to a file descriptor that refers to the new native Android fence + object. This new native Android fence object is signaled when the EGL + Android fence sync object is signaled. + + When the condition of the sync object is satisfied by the fence command, + the sync is signaled by the associated client API context, causing any + eglClientWaitSyncKHR commands (see below) blocking on <sync> to unblock. If + the sync object is an EGL Android fence sync object then the native Android + fence object is also signaled when the condition is satisfied. The + EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR condition is satisfied by completion + of the fence command corresponding to the sync object and all preceding + commands in the associated client API context's command stream. The sync + object will not be signaled until all effects from these commands on the + client API's internal and framebuffer state are fully realized. No other + state is affected by execution of the fence command. + + The EGL_SYNC_ANDROID_FENCE_SIGNALED_ANDROID condition is satisfied by the + signaling of the native Android fence object referred to by the + EGL_SYNC_ANDROID_FENCE_FD_ANDROID attribute. When this happens any + eglClientWaitSyncKHR commands blocking on <sync> unblock." + + Modify the list of eglCreateSyncKHR errors in Section 3.8.1 (Sync Objects), + added by KHR_fence_sync + + "Errors + ------ + + * If <dpy> is not the name of a valid, initialized EGLDisplay, + EGL_NO_SYNC_KHR is returned and an EGL_BAD_DISPLAY error is + generated. + * If <type> is EGL_SYNC_FENCE_KHR and <attrib_list> is neither NULL nor + empty (containing only EGL_NONE), EGL_NO_SYNC_KHR is returned and an + EGL_BAD_ATTRIBUTE error is generated. + * If <type> is EGL_SYNC_ANDROID_FENCE_ANDROID and <attrib_list> contains + an attribute other than EGL_SYNC_ANDROID_FENCE_FD_ANDROID, EGL_NO_SYNC_KHR is + returned and an EGL_BAD_ATTRIBUTE error is generated. + * If <type> is not a supported type of sync object, + EGL_NO_SYNC_KHR is returned and an EGL_BAD_ATTRIBUTE error is + generated. + * If <type> is EGL_SYNC_FENCE_KHR or EGL_SYNC_ANDROID_FENCE_ANDROID and + no context is current for the bound API (i.e., eglGetCurrentContext + returns EGL_NO_CONTEXT), EGL_NO_SYNC_KHR is returned and an + EGL_BAD_MATCH error is generated. + * If <type> is EGL_SYNC_FENCE_KHR or EGL_SYNC_ANDROID_FENCE_ANDROID and + <dpy> does not match the EGLDisplay of the currently bound context for + the currently bound client API (the EGLDisplay returned by + eglGetCurrentDisplay()) then EGL_NO_SYNC_KHR is returned and an + EGL_BAD_MATCH error is generated. + * If <type> is EGL_SYNC_FENCE_KHR or EGL_SYNC_ANDROID_FENCE_ANDROID and + the currently bound client API does not support the client API + extension indicating it can place fence commands, then EGL_NO_SYNC_KHR + is returned and an EGL_BAD_MATCH error is generated." + + Modify table 3.cc in Section 3.8.1 (Sync Objects), added by KHR_fence_sync + + " + Attribute Description Supported Sync Objects + ----------------- ----------------------- ---------------------- + EGL_SYNC_TYPE_KHR Type of the sync object All + EGL_SYNC_STATUS_KHR Status of the sync object All + EGL_SYNC_CONDITION_KHR Signaling condition EGL_SYNC_FENCE_KHR and + EGL_SYNC_ANDROID_FENCE_ANDROID only + " + + Modify the second paragraph description of eglDestroySyncKHR in Section + 3.8.1 (Sync Objects), added by KHR_fence_sync + + "If no errors are generated, EGL_TRUE is returned, and <sync> will no + longer be the handle of a valid sync object. Additionally, if <sync> is an + EGL Android fence sync object and the EGL_SYNC_ANDROID_FENCE_FD_ANDROID + attribute is not EGL_NO_ANDROID_FENCE_ANDROID then that file descriptor is + closed." + + Add the following after the last paragraph of Section 3.8.1 (Sync + Objects), added by KHR_fence_sync + + The command + + EGLint eglDupAndroidFenceFDANDROID( + EGLdisplay dpy, + EGLSyncKHR sync); + + duplicates the file descriptor stored in the + EGL_SYNC_ANDROID_FENCE_FD_ANDROID attribute of an EGL Android fence sync + object and returns the new file descriptor. + + Errors + ------ + + * If <sync> is not a valid sync object for <dpy>, + EGL_NO_ANDROID_FENCE_ANDROID is returned and an EGL_BAD_PARAMETER + error is generated. + * If the EGL_SYNC_ANDROID_FENCE_FD_ANDROID attribute of <sync> is + EGL_NO_ANDROID_FENCE_ANDROID, EGL_NO_ANDROID_FENCE_ANDROID is returned + and an EGL_BAD_PARAMETER error is generated. + * If <dpy> does not match the display passed to eglCreateSyncKHR + when <sync> was created, the behaviour is undefined." + +Issues + + 1. Should EGLSyncKHR objects that wrap Android fence objects use the + EGL_SYNC_FENCE_KHR type? + + RESOLVED: A new sync object type will be added. + + We don't want to require all EGL fence sync objects to wrap Android fence + objects, so we need some way to tell the EGL implementation at sync object + creation whether the sync object should support querying the Android fence + FD attribute. We could do this with either a new sync object type or with a + boolean attribute. It might be nice to pick up future signaling conditions + that might be added for fence sync objects, but there may be things that + get added that don't make sense in the context of Android fence objects. + + 2. Who is responsible for dup'ing the Android fence file descriptors? + + RESOLVED: Whenever a file descriptor is passed into or returned from an + EGL call in this extension, ownership of that file descriptor is + transfered. The recipient of the file descriptor must close it when it is + no longer needed, and the provider of the file descriptor must dup it + before providing it if they require continued use of the native Android + fence. + + 3. Can the EGL_SYNC_ANDROID_FENCE_FD_ANDROID attribute be queried? + + RESOLVED: No. + + Returning the file descriptor owned by the EGL implementation would + violate the file descriptor ownership rule described in issue #2. Having + eglGetSyncAttribKHR return a different (dup'd) file descriptor each time + it's called seems wrong, so a new function was added to explicitly dup the + file descriptor. + + That said, the attribute is useful both as a way to pass an existing file + descriptor to eglCreateSyncKHR and as a way to describe the subsequent + behavior of EGL Android fence sync objects, so it is left as an attribute + for which the value cannot be queried. + +Revision History + +#2 (Jamie Gennis, July 23, 2012) + - Changed the file descriptor ownership transferring behavior. + - Added the eglDupAndroidFenceFDANDROID function. + - Removed EGL_SYNC_ANDROID_FENCE_FD_ANDROID from the table of gettable + attributes. + - Added language specifying that a native Android fence is created at the + flush following the creation of an EGL Android fence sync object that is + not passed an existing native fence. + +#1 (Jamie Gennis, May 29, 2012) + - Initial draft. diff --git a/opengl/specs/README b/opengl/specs/README index 16b278f..af3f165 100644 --- a/opengl/specs/README +++ b/opengl/specs/README @@ -10,4 +10,7 @@ for use by Android extensions. 0x3141 (unused) 0x3142 EGL_ANDROID_recordable 0x3143 EGL_VERSION_HW_ANDROID (internal use) -0x3144 - 0x314F (unused) +0x3144 EGL_SYNC_ANDROID_FENCE_ANDROID +0x3145 EGL_SYNC_FENCE_FD_ANDROID +0x3146 EGL_SYNC_ANDROID_FENCE_SIGNALED_ANDROID +0x3147 - 0x314F (unused) diff --git a/opengl/tests/Android.mk b/opengl/tests/Android.mk index 071c679..3ae3b4e 100644 --- a/opengl/tests/Android.mk +++ b/opengl/tests/Android.mk @@ -20,7 +20,7 @@ dirs := \ textures \ tritex \ -ifneq ($(TARGET_BUILD_PDK), true) +ifneq (,$(TARGET_BUILD_JAVA_SUPPORT_LEVEL)) dirs += \ gl2_cameraeye \ gl2_java \ @@ -29,11 +29,16 @@ dirs += \ gl_jni \ gl_perfapp \ lighting1709 \ - testFramerate \ testLatency \ testPauseResume \ testViewport \ -endif +endif # JAVA_SUPPORT + +ifeq (platform,$(TARGET_BUILD_JAVA_SUPPORT_LEVEL)) +dirs += \ + testFramerate + +endif # JAVA_SUPPORT platform include $(call all-named-subdir-makefiles, $(dirs)) diff --git a/opengl/tests/hwc/hwcColorEquiv.cpp b/opengl/tests/hwc/hwcColorEquiv.cpp index bb305dc..160906d 100644 --- a/opengl/tests/hwc/hwcColorEquiv.cpp +++ b/opengl/tests/hwc/hwcColorEquiv.cpp @@ -124,7 +124,7 @@ const float defaultEndDelay = 2.0; // Default delay after rendering graphics // Globals static const int texUsage = GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_RARELY; -static hwc_composer_device_t *hwcDevice; +static hwc_composer_device_1_t *hwcDevice; static EGLDisplay dpy; static EGLSurface surface; static EGLint width, height; @@ -344,16 +344,16 @@ main(int argc, char *argv[]) hwcTestFillColorHBlend(equivFrame.get(), refFormat->format, startRefColor, endRefColor); - hwc_layer_list_t *list; - size_t size = sizeof(hwc_layer_list) + numFrames * sizeof(hwc_layer_t); - if ((list = (hwc_layer_list_t *) calloc(1, size)) == NULL) { + hwc_display_contents_1_t *list; + size_t size = sizeof(hwc_display_contents_1_t) + numFrames * sizeof(hwc_layer_1_t); + if ((list = (hwc_display_contents_1_t *) calloc(1, size)) == NULL) { testPrintE("Allocate list failed"); exit(11); } list->flags = HWC_GEOMETRY_CHANGED; list->numHwLayers = numFrames; - hwc_layer_t *layer = &list->hwLayers[0]; + hwc_layer_1_t *layer = &list->hwLayers[0]; layer->handle = refFrame->handle; layer->blending = HWC_BLENDING_NONE; layer->sourceCrop.left = 0; @@ -383,7 +383,7 @@ main(int argc, char *argv[]) // Perform prepare operation if (verbose) { testPrintI("Prepare:"); hwcTestDisplayList(list); } - hwcDevice->prepare(hwcDevice, list); + hwcDevice->prepare(hwcDevice, 1, &list); if (verbose) { testPrintI("Post Prepare:"); hwcTestDisplayListPrepareModifiable(list); @@ -393,7 +393,9 @@ main(int argc, char *argv[]) list->flags &= ~HWC_GEOMETRY_CHANGED; if (verbose) {hwcTestDisplayListHandles(list); } - hwcDevice->set(hwcDevice, dpy, surface, list); + list->dpy = dpy; + list->sur = surface; + hwcDevice->set(hwcDevice, 1, &list); testDelay(endDelay); diff --git a/opengl/tests/hwc/hwcCommit.cpp b/opengl/tests/hwc/hwcCommit.cpp index efa646c..3681fbb 100644 --- a/opengl/tests/hwc/hwcCommit.cpp +++ b/opengl/tests/hwc/hwcCommit.cpp @@ -230,7 +230,7 @@ private: // Globals static const int texUsage = GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_RARELY; -static hwc_composer_device_t *hwcDevice; +static hwc_composer_device_1_t *hwcDevice; static EGLDisplay dpy; static EGLSurface surface; static EGLint width, height; @@ -1397,7 +1397,7 @@ void Rational::double2Rational(double f, Range nRange, Range dRange, // Given a list of rectangles, determine how many HWC will commit to render uint32_t numOverlays(list<Rectangle>& rectList) { - hwc_layer_list_t *hwcList; + hwc_display_contents_1_t *hwcList; list<sp<GraphicBuffer> > buffers; hwcList = hwcTestCreateLayerList(rectList.size()); @@ -1406,7 +1406,7 @@ uint32_t numOverlays(list<Rectangle>& rectList) exit(30); } - hwc_layer_t *layer = &hwcList->hwLayers[0]; + hwc_layer_1_t *layer = &hwcList->hwLayers[0]; for (std::list<Rectangle>::iterator it = rectList.begin(); it != rectList.end(); ++it, ++layer) { // Allocate the texture for the source frame @@ -1430,7 +1430,7 @@ uint32_t numOverlays(list<Rectangle>& rectList) // Perform prepare operation if (verbose) { testPrintI("Prepare:"); hwcTestDisplayList(hwcList); } - hwcDevice->prepare(hwcDevice, hwcList); + hwcDevice->prepare(hwcDevice, 1, &hwcList); if (verbose) { testPrintI("Post Prepare:"); hwcTestDisplayListPrepareModifiable(hwcList); diff --git a/opengl/tests/hwc/hwcRects.cpp b/opengl/tests/hwc/hwcRects.cpp index 906c169..ec0403f 100644 --- a/opengl/tests/hwc/hwcRects.cpp +++ b/opengl/tests/hwc/hwcRects.cpp @@ -165,7 +165,7 @@ public: list<Rectangle> rectangle; static const int texUsage = GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_RARELY; -static hwc_composer_device_t *hwcDevice; +static hwc_composer_device_1_t *hwcDevice; static EGLDisplay dpy; static EGLSurface surface; static EGLint width, height; @@ -307,14 +307,14 @@ main(int argc, char *argv[]) } // Create list of frames - hwc_layer_list_t *list; + hwc_display_contents_1_t *list; list = hwcTestCreateLayerList(rectangle.size()); if (list == NULL) { testPrintE("hwcTestCreateLayerList failed"); exit(5); } - hwc_layer_t *layer = &list->hwLayers[0]; + hwc_layer_1_t *layer = &list->hwLayers[0]; for (std::list<Rectangle>::iterator it = rectangle.begin(); it != rectangle.end(); ++it, ++layer) { layer->handle = it->texture->handle; @@ -329,7 +329,7 @@ main(int argc, char *argv[]) // Perform prepare operation if (verbose) { testPrintI("Prepare:"); hwcTestDisplayList(list); } - hwcDevice->prepare(hwcDevice, list); + hwcDevice->prepare(hwcDevice, 1, &list); if (verbose) { testPrintI("Post Prepare:"); hwcTestDisplayListPrepareModifiable(list); @@ -341,7 +341,9 @@ main(int argc, char *argv[]) // Perform the set operation(s) if (verbose) {testPrintI("Set:"); } if (verbose) { hwcTestDisplayListHandles(list); } - hwcDevice->set(hwcDevice, dpy, surface, list); + list->dpy = dpy; + list->sur = surface; + hwcDevice->set(hwcDevice, 1, &list); testDelay(endDelay); diff --git a/opengl/tests/hwc/hwcStress.cpp b/opengl/tests/hwc/hwcStress.cpp index b02a424..3e8ea8d 100644 --- a/opengl/tests/hwc/hwcStress.cpp +++ b/opengl/tests/hwc/hwcStress.cpp @@ -192,7 +192,7 @@ const vector<unsigned int> vecTransformFlags(transformFlags, // File scope globals static const int texUsage = GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_RARELY; -static hwc_composer_device_t *hwcDevice; +static hwc_composer_device_1_t *hwcDevice; static EGLDisplay dpy; static EGLSurface surface; static EGLint width, height; @@ -409,7 +409,7 @@ main(int argc, char *argv[]) // generated for this pass. srand48(pass); - hwc_layer_list_t *list; + hwc_display_contents_1_t *list; list = hwcTestCreateLayerList(testRandMod(frames.size()) + 1); if (list == NULL) { testPrintE("hwcTestCreateLayerList failed"); @@ -428,7 +428,7 @@ main(int argc, char *argv[]) for (unsigned int n1 = 0; n1 < list->numHwLayers; n1++) { unsigned int idx = testRandMod(selectedFrames[n1].size()); sp<GraphicBuffer> gBuf = selectedFrames[n1][idx]; - hwc_layer_t *layer = &list->hwLayers[n1]; + hwc_layer_1_t *layer = &list->hwLayers[n1]; layer->handle = gBuf->handle; layer->blending = blendingOps[testRandMod(NUMA(blendingOps))]; @@ -478,7 +478,7 @@ main(int argc, char *argv[]) // Perform prepare operation if (verbose) { testPrintI("Prepare:"); hwcTestDisplayList(list); } - hwcDevice->prepare(hwcDevice, list); + hwcDevice->prepare(hwcDevice, 1, &list); if (verbose) { testPrintI("Post Prepare:"); hwcTestDisplayListPrepareModifiable(list); @@ -491,13 +491,15 @@ main(int argc, char *argv[]) if (verbose) {testPrintI("Set:"); } for (unsigned int n1 = 0; n1 < numSet; n1++) { if (verbose) { hwcTestDisplayListHandles(list); } - hwcDevice->set(hwcDevice, dpy, surface, list); + list->dpy = dpy; + list->sur = surface; + hwcDevice->set(hwcDevice, 1, &list); // Prandomly select a new set of handles for (unsigned int n1 = 0; n1 < list->numHwLayers; n1++) { unsigned int idx = testRandMod(selectedFrames[n1].size()); sp<GraphicBuffer> gBuf = selectedFrames[n1][idx]; - hwc_layer_t *layer = &list->hwLayers[n1]; + hwc_layer_1_t *layer = &list->hwLayers[n1]; layer->handle = (native_handle_t *) gBuf->handle; } diff --git a/opengl/tests/hwc/hwcTestLib.cpp b/opengl/tests/hwc/hwcTestLib.cpp index 28e0c3f..d567e6e 100644 --- a/opengl/tests/hwc/hwcTestLib.cpp +++ b/opengl/tests/hwc/hwcTestLib.cpp @@ -134,7 +134,7 @@ void hwcTestInitDisplay(bool verbose, EGLDisplay *dpy, EGLSurface *surface, } // Open Hardware Composer Device -void hwcTestOpenHwc(hwc_composer_device_t **hwcDevicePtr) +void hwcTestOpenHwc(hwc_composer_device_1_t **hwcDevicePtr) { int rv; hw_module_t const *hwcModule; @@ -145,7 +145,7 @@ void hwcTestOpenHwc(hwc_composer_device_t **hwcDevicePtr) perror(NULL); exit(77); } - if ((rv = hwc_open(hwcModule, hwcDevicePtr)) != 0) { + if ((rv = hwc_open_1(hwcModule, hwcDevicePtr)) != 0) { testPrintE("hwc_open failed, rv: %i", rv); errno = -rv; perror(NULL); @@ -399,12 +399,12 @@ const char *hwcTestGraphicFormat2str(uint32_t format) * Dynamically creates layer list with numLayers worth * of hwLayers entries. */ -hwc_layer_list_t *hwcTestCreateLayerList(size_t numLayers) +hwc_display_contents_1_t *hwcTestCreateLayerList(size_t numLayers) { - hwc_layer_list_t *list; + hwc_display_contents_1_t *list; - size_t size = sizeof(hwc_layer_list) + numLayers * sizeof(hwc_layer_t); - if ((list = (hwc_layer_list_t *) calloc(1, size)) == NULL) { + size_t size = sizeof(hwc_display_contents_1_t) + numLayers * sizeof(hwc_layer_1_t); + if ((list = (hwc_display_contents_1_t *) calloc(1, size)) == NULL) { return NULL; } list->flags = HWC_GEOMETRY_CHANGED; @@ -417,13 +417,13 @@ hwc_layer_list_t *hwcTestCreateLayerList(size_t numLayers) * hwcTestFreeLayerList * Frees memory previous allocated via hwcTestCreateLayerList(). */ -void hwcTestFreeLayerList(hwc_layer_list_t *list) +void hwcTestFreeLayerList(hwc_display_contents_1_t *list) { free(list); } // Display the settings of the layer list pointed to by list -void hwcTestDisplayList(hwc_layer_list_t *list) +void hwcTestDisplayList(hwc_display_contents_1_t *list) { testPrintI(" flags: %#x%s", list->flags, (list->flags & HWC_GEOMETRY_CHANGED) ? " GEOMETRY_CHANGED" : ""); @@ -494,7 +494,7 @@ void hwcTestDisplayList(hwc_layer_list_t *list) * Displays the portions of a list that are meant to be modified by * a prepare call. */ -void hwcTestDisplayListPrepareModifiable(hwc_layer_list_t *list) +void hwcTestDisplayListPrepareModifiable(hwc_display_contents_1_t *list) { uint32_t numOverlays = 0; for (unsigned int layer = 0; layer < list->numHwLayers; layer++) { @@ -522,7 +522,7 @@ void hwcTestDisplayListPrepareModifiable(hwc_layer_list_t *list) * * Displays the handles of all the graphic buffers in the list. */ -void hwcTestDisplayListHandles(hwc_layer_list_t *list) +void hwcTestDisplayListHandles(hwc_display_contents_1_t *list) { const unsigned int maxLayersPerLine = 6; diff --git a/opengl/tests/hwc/hwcTestLib.h b/opengl/tests/hwc/hwcTestLib.h index b0c3012..d7d5837 100644 --- a/opengl/tests/hwc/hwcTestLib.h +++ b/opengl/tests/hwc/hwcTestLib.h @@ -107,17 +107,17 @@ class HwcTestDim { // Function Prototypes void hwcTestInitDisplay(bool verbose, EGLDisplay *dpy, EGLSurface *surface, EGLint *width, EGLint *height); -void hwcTestOpenHwc(hwc_composer_device_t **hwcDevicePtr); +void hwcTestOpenHwc(hwc_composer_device_1_t **hwcDevicePtr); const struct hwcTestGraphicFormat *hwcTestGraphicFormatLookup(const char *desc); const struct hwcTestGraphicFormat *hwcTestGraphicFormatLookup(uint32_t id); const char *hwcTestGraphicFormat2str(uint32_t format); std::string hwcTestRect2str(const struct hwc_rect& rect); -hwc_layer_list_t *hwcTestCreateLayerList(size_t numLayers); -void hwcTestFreeLayerList(hwc_layer_list_t *list); -void hwcTestDisplayList(hwc_layer_list_t *list); -void hwcTestDisplayListPrepareModifiable(hwc_layer_list_t *list); -void hwcTestDisplayListHandles(hwc_layer_list_t *list); +hwc_display_contents_1_t *hwcTestCreateLayerList(size_t numLayers); +void hwcTestFreeLayerList(hwc_display_contents_1_t *list); +void hwcTestDisplayList(hwc_display_contents_1_t *list); +void hwcTestDisplayListPrepareModifiable(hwc_display_contents_1_t *list); +void hwcTestDisplayListHandles(hwc_display_contents_1_t *list); uint32_t hwcTestColor2Pixel(uint32_t format, ColorFract color, float alpha); void hwcTestColorConvert(uint32_t fromFormat, uint32_t toFormat, diff --git a/opengl/tools/glgen/gen b/opengl/tools/glgen/gen index 31f4190..3359a22 100755 --- a/opengl/tools/glgen/gen +++ b/opengl/tools/glgen/gen @@ -12,6 +12,7 @@ mkdir -p out/javax/microedition/khronos/opengles mkdir -p out/com/google/android/gles_jni mkdir -p out/android/app mkdir -p out/android/graphics +mkdir -p out/android/view mkdir -p out/android/opengl mkdir -p out/android/content mkdir -p out/android/content/pm @@ -24,15 +25,33 @@ echo "public interface Canvas {}" >> out/android/graphics/Canvas.java echo "package android.app; import android.content.pm.IPackageManager; public class AppGlobals { public static IPackageManager getPackageManager() { return null;} }" > out/android/app/AppGlobals.java # echo "package android.content; import android.content.pm.PackageManager; public interface Context { public PackageManager getPackageManager(); }" > out/android/content/Context.java echo "package android.content.pm; public class ApplicationInfo {public int targetSdkVersion;}" > out/android/content/pm/ApplicationInfo.java -echo "package android.content.pm; public interface IPackageManager {ApplicationInfo getApplicationInfo(java.lang.String packageName, int flags) throws android.os.RemoteException;}" > out/android/content/pm/IPackageManager.java +echo "package android.content.pm; public interface IPackageManager {ApplicationInfo getApplicationInfo(java.lang.String packageName, int flags, java.lang.String userId) throws android.os.RemoteException;}" > out/android/content/pm/IPackageManager.java echo "package android.os; public class Build {public static class VERSION_CODES { public static final int CUPCAKE = 3;}; }" > out/android/os/Build.java +echo "package android.os; public class UserId {public static String myUserId() { return \"\"; } }" > out/android/os/UserId.java echo "package android.os; public class RemoteException extends Exception {}" > out/android/os/RemoteException.java echo "package android.util; public class Log {public static void w(String a, String b) {} public static void e(String a, String b) {}}" > out/android/util/Log.java +echo "package android.opengl; public abstract class EGLObjectHandle { public int getHandle() { return 0; } }" > out/android/opengl/EGLObjectHandle.java +echo "package android.opengl; public class EGLSurface extends EGLObjectHandle { }" > out/android/opengl/EGLSurface.java +echo "package android.opengl; public class EGLContext extends EGLObjectHandle { }" > out/android/opengl/EGLContext.java +echo "package android.opengl; public class EGLDisplay extends EGLObjectHandle { }" > out/android/opengl/EGLDisplay.java +echo "package android.opengl; public class EGLConfig extends EGLObjectHandle { }" > out/android/opengl/EGLConfig.java + + +echo "package android.graphics;" > out/android/graphics/SurfaceTexture.java +echo "public interface SurfaceTexture {}" >> out/android/graphics/SurfaceTexture.java +echo "package android.view;" > out/android/view/SurfaceView.java +echo "public interface SurfaceView { SurfaceHolder getHolder(); }" >> out/android/view/SurfaceView.java +echo "package android.view;" > out/android/view/Surface.java +echo "public interface Surface {}" >> out/android/view/Surface.java +echo "package android.view;" > out/android/view/SurfaceHolder.java +echo "public interface SurfaceHolder { Surface getSurface(); }" >> out/android/view/SurfaceHolder.java + + GLFILE=out/javax/microedition/khronos/opengles/GL.java cp stubs/jsr239/GLHeader.java-if $GLFILE -GLGEN_FILES="CFunc.java CType.java CodeEmitter.java GenerateGL.java GenerateGLES.java GLESCodeEmitter.java JFunc.java JniCodeEmitter.java JType.java Jsr239CodeEmitter.java ParameterChecker.java" +GLGEN_FILES="CFunc.java CType.java CodeEmitter.java EGLCodeEmitter.java GenerateEGL.java GenerateGL.java GenerateGLES.java GLESCodeEmitter.java JFunc.java JniCodeEmitter.java JType.java Jsr239CodeEmitter.java ParameterChecker.java" pushd src > /dev/null javac ${GLGEN_FILES} @@ -59,11 +78,19 @@ if [ $JAVA_RESULT -ne 0 ]; then exit $JAVA_RESULT fi +echo "Generating static EGL 1.4 bindings" +java -classpath src GenerateEGL +JAVA_RESULT=$? +if [ $JAVA_RESULT -ne 0 ]; then + echo "Could not run GenerateEGL." + exit $JAVA_RESULT +fi + rm src/*.class pushd out > /dev/null mkdir classes -javac -d classes com/google/android/gles_jni/GLImpl.java javax/microedition/khronos/opengles/GL10.java javax/microedition/khronos/opengles/GL10Ext.java javax/microedition/khronos/opengles/GL11.java javax/microedition/khronos/opengles/GL11Ext.java javax/microedition/khronos/opengles/GL11ExtensionPack.java android/opengl/GLES10.java android/opengl/GLES10Ext.java android/opengl/GLES11.java android/opengl/GLES11Ext.java android/opengl/GLES20.java +javac -d classes android/opengl/EGL14.java com/google/android/gles_jni/GLImpl.java javax/microedition/khronos/opengles/GL10.java javax/microedition/khronos/opengles/GL10Ext.java javax/microedition/khronos/opengles/GL11.java javax/microedition/khronos/opengles/GL11Ext.java javax/microedition/khronos/opengles/GL11ExtensionPack.java android/opengl/GLES10.java android/opengl/GLES10Ext.java android/opengl/GLES11.java android/opengl/GLES11Ext.java android/opengl/GLES20.java popd > /dev/null JAVA_RESULT=$? if [ $JAVA_RESULT -ne 0 ]; then @@ -90,6 +117,7 @@ compareGenerated() { if cmp -s $1/$3 $2/$3 ; then echo "# " $3 unchanged else + echo "# " $3 changed if [ $SAID_PLEASE == "0" ] ; then echo Please evaluate the following commands: echo @@ -101,18 +129,18 @@ compareGenerated() { fi } -compareGenerated ../../../core/jni generated/C com_google_android_gles_jni_GLImpl.cpp -compareGenerated ../../java/com/google/android/gles_jni generated/com/google/android/gles_jni GLImpl.java +compareGenerated ../../../../base/core/jni generated/C com_google_android_gles_jni_GLImpl.cpp +compareGenerated ../../../../base/opengl/java/com/google/android/gles_jni generated/com/google/android/gles_jni GLImpl.java for x in GL.java GL10.java GL10Ext.java GL11.java GL11Ext.java GL11ExtensionPack.java do - compareGenerated ../../java/javax/microedition/khronos/opengles generated/javax/microedition/khronos/opengles $x + compareGenerated ../../../../base/opengl/java/javax/microedition/khronos/opengles generated/javax/microedition/khronos/opengles $x done -for x in GLES10 GLES10Ext GLES11 GLES11Ext GLES20 +for x in EGL14 GLES10 GLES10Ext GLES11 GLES11Ext GLES20 do - compareGenerated ../../java/android/opengl generated/android/opengl ${x}.java - compareGenerated ../../../core/jni generated/C android_opengl_${x}.cpp + compareGenerated ../../../../base/opengl/java/android/opengl generated/android/opengl ${x}.java + compareGenerated ../../../../base/core/jni generated/C android_opengl_${x}.cpp done if [ $KEEP_GENERATED == "0" ] ; then diff --git a/opengl/tools/glgen/specs/egl/EGL14.spec b/opengl/tools/glgen/specs/egl/EGL14.spec new file mode 100644 index 0000000..828e114 --- /dev/null +++ b/opengl/tools/glgen/specs/egl/EGL14.spec @@ -0,0 +1,33 @@ +EGLint eglGetError ( void ) +EGLDisplay eglGetDisplay ( EGLNativeDisplayType display_id ) +EGLBoolean eglInitialize ( EGLDisplay dpy, EGLint *major, EGLint *minor ) +EGLBoolean eglTerminate ( EGLDisplay dpy ) +const char * eglQueryString ( EGLDisplay dpy, EGLint name ) +EGLBoolean eglGetConfigs ( EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config ) +EGLBoolean eglChooseConfig ( EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config ) +EGLBoolean eglGetConfigAttrib ( EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value ) +EGLSurface eglCreateWindowSurface ( EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list ) +EGLSurface eglCreatePbufferSurface ( EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list ) +EGLSurface eglCreatePixmapSurface ( EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list ) +EGLBoolean eglDestroySurface ( EGLDisplay dpy, EGLSurface surface ) +EGLBoolean eglQuerySurface ( EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value ) +EGLBoolean eglBindAPI ( EGLenum api ) +EGLenum eglQueryAPI ( void ) +EGLBoolean eglWaitClient ( void ) +EGLBoolean eglReleaseThread ( void ) +EGLSurface eglCreatePbufferFromClientBuffer ( EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list ) +EGLBoolean eglSurfaceAttrib ( EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value ) +EGLBoolean eglBindTexImage ( EGLDisplay dpy, EGLSurface surface, EGLint buffer ) +EGLBoolean eglReleaseTexImage ( EGLDisplay dpy, EGLSurface surface, EGLint buffer ) +EGLBoolean eglSwapInterval ( EGLDisplay dpy, EGLint interval ) +EGLContext eglCreateContext ( EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list ) +EGLBoolean eglDestroyContext ( EGLDisplay dpy, EGLContext ctx ) +EGLBoolean eglMakeCurrent ( EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx ) +EGLContext eglGetCurrentContext ( void ) +EGLSurface eglGetCurrentSurface ( EGLint readdraw ) +EGLDisplay eglGetCurrentDisplay ( void ) +EGLBoolean eglQueryContext ( EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value ) +EGLBoolean eglWaitGL ( void ) +EGLBoolean eglWaitNative ( EGLint engine ) +EGLBoolean eglSwapBuffers ( EGLDisplay dpy, EGLSurface surface ) +EGLBoolean eglCopyBuffers ( EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target ) diff --git a/opengl/tools/glgen/specs/egl/checks.spec b/opengl/tools/glgen/specs/egl/checks.spec new file mode 100644 index 0000000..34fb1ee --- /dev/null +++ b/opengl/tools/glgen/specs/egl/checks.spec @@ -0,0 +1,13 @@ +eglInitialize check major 1 check minor 1 +eglGetConfigs check configs config_size +eglChooseConfig check configs config_size check num_config 1 sentinel attrib_list EGL_NONE +eglGetConfigAttrib check value 1 +//STUB function: //eglCreateWindowSurface sentinel attrib_list EGL_NONE +eglCreatePbufferSurface sentinel attrib_list EGL_NONE +//unsupported: eglCreatePixmapSurface sentinel attrib_list EGL_NONE +eglCreatePixmapSurface unsupported +eglCopyBuffers unsupported +eglQuerySurface check value 1 +eglCreatePbufferFromClientBuffer sentinel attrib_list EGL_NONE +eglCreateContext sentinel attrib_list EGL_NONE +eglQueryContext check value 1 diff --git a/opengl/tools/glgen/src/CFunc.java b/opengl/tools/glgen/src/CFunc.java index 4847694..a192c00 100644 --- a/opengl/tools/glgen/src/CFunc.java +++ b/opengl/tools/glgen/src/CFunc.java @@ -28,6 +28,7 @@ public class CFunc { boolean hasPointerArg = false; boolean hasTypedPointerArg = false; + boolean hasEGLHandleArg = false; public CFunc(String original) { this.original = original; @@ -63,6 +64,9 @@ public class CFunc { if (argType.isTypedPointer()) { hasTypedPointerArg = true; } + if (argType.isEGLHandle()) { + hasEGLHandleArg = true; + } } public int getNumArgs() { @@ -95,6 +99,10 @@ public class CFunc { return hasTypedPointerArg; } + public boolean hasEGLHandleArg() { + return hasEGLHandleArg; + } + @Override public String toString() { String s = "Function " + fname + " returns " + ftype + ": "; diff --git a/opengl/tools/glgen/src/CType.java b/opengl/tools/glgen/src/CType.java index e0f0ca6..92950ea 100644 --- a/opengl/tools/glgen/src/CType.java +++ b/opengl/tools/glgen/src/CType.java @@ -53,6 +53,16 @@ public class CType { return isPointer; } + public boolean isEGLHandle() { + if(baseType.equals("EGLContext") + || baseType.equals("EGLConfig") + || baseType.equals("EGLSurface") + || baseType.equals("EGLDisplay")) { + return true; + } + return false; + } + boolean isVoid() { String baseType = getBaseType(); return baseType.equals("GLvoid") || diff --git a/opengl/tools/glgen/src/EGLCodeEmitter.java b/opengl/tools/glgen/src/EGLCodeEmitter.java new file mode 100644 index 0000000..300f776 --- /dev/null +++ b/opengl/tools/glgen/src/EGLCodeEmitter.java @@ -0,0 +1,58 @@ +/* + * Copyright 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.io.PrintStream; + +/** + * Emits a Java interface and Java & C implementation for a C function. + * + * <p> The Java interface will have Buffer and array variants for functions that + * have a typed pointer argument. The array variant will convert a single "<type> *data" + * argument to a pair of arguments "<type>[] data, int offset". + */ +public class EGLCodeEmitter extends JniCodeEmitter { + + PrintStream mJavaImplStream; + PrintStream mCStream; + + PrintStream mJavaInterfaceStream; + + /** + */ + public EGLCodeEmitter(String classPathName, + ParameterChecker checker, + PrintStream javaImplStream, + PrintStream cStream) { + mClassPathName = classPathName; + mChecker = checker; + + mJavaImplStream = javaImplStream; + mCStream = cStream; + mUseContextPointer = false; + mUseStaticMethods = true; + mUseSimpleMethodNames = true; + mUseHideCommentForAPI = false; + } + + public void emitCode(CFunc cfunc, String original) { + emitCode(cfunc, original, null, mJavaImplStream, + mCStream); + } + + public void emitNativeRegistration(String nativeRegistrationName) { + emitNativeRegistration(nativeRegistrationName, mCStream); + } +} diff --git a/opengl/tools/glgen/src/GenerateEGL.java b/opengl/tools/glgen/src/GenerateEGL.java new file mode 100644 index 0000000..aaa748c --- /dev/null +++ b/opengl/tools/glgen/src/GenerateEGL.java @@ -0,0 +1,109 @@ +/* + * Copyright 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.PrintStream; + +public class GenerateEGL { + + private static void copy(String filename, PrintStream out) throws IOException { + BufferedReader br = new BufferedReader(new FileReader(filename)); + String s; + while ((s = br.readLine()) != null) { + out.println(s); + } + } + + private static void emit(EGLCodeEmitter emitter, + BufferedReader specReader, + PrintStream glStream, + PrintStream cStream) throws Exception { + String s = null; + while ((s = specReader.readLine()) != null) { + if (s.trim().startsWith("//")) { + continue; + } + + CFunc cfunc = CFunc.parseCFunc(s); + + String fname = cfunc.getName(); + String stubRoot = "stubs/egl/" + fname; + String javaPath = stubRoot + ".java"; + File f = new File(javaPath); + if (f.exists()) { + System.out.println("Special-casing function " + fname); + copy(javaPath, glStream); + copy(stubRoot + ".cpp", cStream); + + // Register native function names + // This should be improved to require fewer discrete files + String filename = stubRoot + ".nativeReg"; + BufferedReader br = + new BufferedReader(new FileReader(filename)); + String nfunc; + while ((nfunc = br.readLine()) != null) { + emitter.addNativeRegistration(nfunc); + } + } else { + emitter.emitCode(cfunc, s); + } + } + } + + public static void main(String[] args) throws Exception { + int aidx = 0; + while ((aidx < args.length) && (args[aidx].charAt(0) == '-')) { + switch (args[aidx].charAt(1)) { + default: + System.err.println("Unknown flag: " + args[aidx]); + System.exit(1); + } + + aidx++; + } + + BufferedReader checksReader = + new BufferedReader(new FileReader("specs/egl/checks.spec")); + ParameterChecker checker = new ParameterChecker(checksReader); + + + BufferedReader specReader = + new BufferedReader(new FileReader("specs/egl/EGL14.spec")); + + String egljFilename = "android/opengl/EGL14.java"; + String eglcFilename = "android_opengl_EGL14.cpp"; + PrintStream egljStream = + new PrintStream(new FileOutputStream("out/" + egljFilename)); + PrintStream eglcStream = + new PrintStream(new FileOutputStream("out/" + eglcFilename)); + egljStream.println("/*"); + eglcStream.println("/*"); + copy("stubs/egl/EGL14Header.java-if", egljStream); + copy("stubs/egl/EGL14cHeader.cpp", eglcStream); + EGLCodeEmitter emitter = new EGLCodeEmitter( + "android/opengl/EGL14", + checker, egljStream, eglcStream); + emit(emitter, specReader, egljStream, eglcStream); + emitter.emitNativeRegistration("register_android_opengl_jni_EGL14"); + egljStream.println("}"); + egljStream.close(); + eglcStream.close(); + } +} diff --git a/opengl/tools/glgen/src/JType.java b/opengl/tools/glgen/src/JType.java index deb2f01..3f7cb73 100644 --- a/opengl/tools/glgen/src/JType.java +++ b/opengl/tools/glgen/src/JType.java @@ -48,6 +48,22 @@ public class JType { typeMapping.put(new CType("char", true, true), new JType("String", false, false)); typeMapping.put(new CType("int"), new JType("int")); + // EGL primitive types + typeMapping.put(new CType("EGLint"), new JType("int")); + typeMapping.put(new CType("EGLBoolean"), new JType("boolean")); + typeMapping.put(new CType("EGLenum"), new JType("int")); + typeMapping.put(new CType("EGLNativePixmapType"), new JType("int")); + typeMapping.put(new CType("EGLNativeWindowType"), new JType("int")); + typeMapping.put(new CType("EGLNativeDisplayType"), new JType("int")); + typeMapping.put(new CType("EGLClientBuffer"), new JType("int")); + + // EGL nonprimitive types + typeMapping.put(new CType("EGLConfig"), new JType("EGLConfig", true, false)); + typeMapping.put(new CType("EGLContext"), new JType("EGLContext", true, false)); + typeMapping.put(new CType("EGLDisplay"), new JType("EGLDisplay", true, false)); + typeMapping.put(new CType("EGLSurface"), new JType("EGLSurface", true, false)); + + // Untyped pointers map to untyped Buffers typeMapping.put(new CType("GLvoid", true, true), new JType("java.nio.Buffer", true, false)); @@ -88,7 +104,7 @@ public class JType { arrayTypeMapping.put(new CType("char", false, true), new JType("byte", false, true)); arrayTypeMapping.put(new CType("GLboolean", false, true), - new JType("boolean", false, true)); + new JType("boolean", false, true)); arrayTypeMapping.put(new CType("GLenum", false, true), new JType("int", false, true)); arrayTypeMapping.put(new CType("GLfixed", true, true), new JType("int", false, true)); arrayTypeMapping.put(new CType("GLfixed", false, true), new JType("int", false, true)); @@ -103,6 +119,13 @@ public class JType { arrayTypeMapping.put(new CType("GLuint", true, true), new JType("int", false, true)); arrayTypeMapping.put(new CType("GLintptr"), new JType("int", false, true)); arrayTypeMapping.put(new CType("GLsizeiptr"), new JType("int", false, true)); + + //EGL typed pointers map to arrays + offsets + arrayTypeMapping.put(new CType("EGLint", false, true), new JType("int", false, true)); + arrayTypeMapping.put(new CType("EGLint", true, true), new JType("int", false, true)); + arrayTypeMapping.put(new CType("EGLConfig", false, true), new JType("EGLConfig", true, true)); + arrayTypeMapping.put(new CType("EGLConfig", true, true), new JType("EGLConfig", true, true)); + } public JType() { @@ -158,6 +181,11 @@ public class JType { (baseType.indexOf("Buffer") != -1); } + public boolean isEGLHandle() { + return !isPrimitive() && + (baseType.startsWith("EGL")); + } + public static JType convert(CType ctype, boolean useArray) { JType javaType = null; if (useArray) { diff --git a/opengl/tools/glgen/src/JniCodeEmitter.java b/opengl/tools/glgen/src/JniCodeEmitter.java index 9fa2b74..774f40c 100644 --- a/opengl/tools/glgen/src/JniCodeEmitter.java +++ b/opengl/tools/glgen/src/JniCodeEmitter.java @@ -25,6 +25,8 @@ public class JniCodeEmitter { static final boolean mUseCPlusPlus = true; protected boolean mUseContextPointer = true; protected boolean mUseStaticMethods = false; + protected boolean mUseSimpleMethodNames = false; + protected boolean mUseHideCommentForAPI = false; protected String mClassPathName; protected ParameterChecker mChecker; protected List<String> nativeRegistrations = new ArrayList<String>(); @@ -34,7 +36,9 @@ public class JniCodeEmitter { public static String getJniName(JType jType) { String jniName = ""; - if (jType.isClass()) { + if (jType.isEGLHandle()) { + return (jType.isArray() ? "[" : "" ) + "Landroid/opengl/" + jType.getBaseType() + ";"; + } else if (jType.isClass()) { return "L" + jType.getBaseType() + ";"; } else if (jType.isArray()) { jniName = "["; @@ -63,7 +67,6 @@ public class JniCodeEmitter { return jniName; } - public void emitCode(CFunc cfunc, String original, PrintStream javaInterfaceStream, PrintStream javaImplStream, @@ -96,6 +99,10 @@ public class JniCodeEmitter { if (!duplicate) { emitJniCode(jfunc, cStream); } + // Don't create IOBuffer versions of the EGL functions + if (cfunc.hasEGLHandleArg()) { + return; + } } jfunc = JFunc.convert(cfunc, false); @@ -121,8 +128,13 @@ public class JniCodeEmitter { } public void emitNativeDeclaration(JFunc jfunc, PrintStream out) { - out.println(" // C function " + jfunc.getCFunc().getOriginal()); - out.println(); + if (mUseHideCommentForAPI) { + out.println(" /* @hide C function " + jfunc.getCFunc().getOriginal() + " */"); + out.println(); + } else { + out.println(" // C function " + jfunc.getCFunc().getOriginal()); + out.println(); + } emitFunction(jfunc, out, true, false); } @@ -197,15 +209,17 @@ public class JniCodeEmitter { out.println(iii + "}"); out.println(iii + "if (" + remaining + " < _needed) {"); - if (emitExceptionCheck) { - out.println(iii + indent + "_exception = 1;"); - } - out.println(iii + indent + "jniThrowException(_env, " + - "\"java/lang/IllegalArgumentException\", " + - "\"" + (isBuffer ? "remaining()" : "length - " + offset) + " < needed\");"); + out.println(iii + indent + "_exception = 1;"); + out.println(iii + indent + + "_exceptionType = \"java/lang/IllegalArgumentException\";"); + out.println(iii + indent + + "_exceptionMessage = \"" + + (isBuffer ? "remaining()" : "length - " + offset) + + " < needed\";"); out.println(iii + indent + "goto exit;"); - needsExit = true; out.println(iii + "}"); + + needsExit = true; } boolean isNullAllowed(CFunc cfunc) { @@ -213,28 +227,70 @@ public class JniCodeEmitter { int index = 1; if (checks != null) { while (index < checks.length) { - if (checks[index].equals("return")) { - index += 2; - } else if (checks[index].startsWith("check")) { - index += 3; - } else if (checks[index].equals("ifcheck")) { - index += 5; - } else if (checks[index].equals("unsupported")) { - index += 1; - } else if (checks[index].equals("requires")) { - index += 2; - } else if (checks[index].equals("nullAllowed")) { + if (checks[index].equals("nullAllowed")) { return true; } else { - System.out.println("Error: unknown keyword \"" + - checks[index] + "\""); - System.exit(0); + index = skipOneCheck(checks, index); } } } return false; } + boolean hasCheckTest(CFunc cfunc) { + String[] checks = mChecker.getChecks(cfunc.getName()); + int index = 1; + if (checks != null) { + while (index < checks.length) { + if (checks[index].startsWith("check")) { + return true; + } else { + index = skipOneCheck(checks, index); + } + } + } + return false; + } + + boolean hasIfTest(CFunc cfunc) { + String[] checks = mChecker.getChecks(cfunc.getName()); + int index = 1; + if (checks != null) { + while (index < checks.length) { + if (checks[index].startsWith("ifcheck")) { + return true; + } else { + index = skipOneCheck(checks, index); + } + } + } + return false; + } + + int skipOneCheck(String[] checks, int index) { + if (checks[index].equals("return")) { + index += 2; + } else if (checks[index].startsWith("check")) { + index += 3; + } else if (checks[index].startsWith("sentinel")) { + index += 3; + } else if (checks[index].equals("ifcheck")) { + index += 5; + } else if (checks[index].equals("unsupported")) { + index += 1; + } else if (checks[index].equals("requires")) { + index += 2; + } else if (checks[index].equals("nullAllowed")) { + index += 1; + } else { + System.out.println("Error: unknown keyword \"" + + checks[index] + "\""); + System.exit(0); + } + + return index; + } + String getErrorReturnValue(CFunc cfunc) { CType returnType = cfunc.getType(); boolean isVoid = returnType.isVoid(); @@ -242,6 +298,10 @@ public class JniCodeEmitter { return null; } + if (returnType.getBaseType().startsWith("EGL")) { + return "(" + returnType.getDeclaration() + ") 0"; + } + String[] checks = mChecker.getChecks(cfunc.getName()); int index = 1; @@ -249,20 +309,8 @@ public class JniCodeEmitter { while (index < checks.length) { if (checks[index].equals("return")) { return checks[index + 1]; - } else if (checks[index].startsWith("check")) { - index += 3; - } else if (checks[index].equals("ifcheck")) { - index += 5; - } else if (checks[index].equals("unsupported")) { - index += 1; - } else if (checks[index].equals("requires")) { - index += 2; - } else if (checks[index].equals("nullAllowed")) { - index += 1; } else { - System.out.println("Error: unknown keyword \"" + - checks[index] + "\""); - System.exit(0); + index = skipOneCheck(checks, index); } } } @@ -277,20 +325,8 @@ public class JniCodeEmitter { while (index < checks.length) { if (checks[index].equals("unsupported")) { return true; - } else if (checks[index].equals("requires")) { - index += 2; - } else if (checks[index].equals("return")) { - index += 2; - } else if (checks[index].startsWith("check")) { - index += 3; - } else if (checks[index].equals("ifcheck")) { - index += 5; - } else if (checks[index].equals("nullAllowed")) { - index += 1; } else { - System.out.println("Error: unknown keyword \"" + - checks[index] + "\""); - System.exit(0); + index = skipOneCheck(checks, index); } } } @@ -302,22 +338,10 @@ public class JniCodeEmitter { int index = 1; if (checks != null) { while (index < checks.length) { - if (checks[index].equals("unsupported")) { - index += 1; - } else if (checks[index].equals("requires")) { + if (checks[index].equals("requires")) { return checks[index+1]; - } else if (checks[index].equals("return")) { - index += 2; - } else if (checks[index].startsWith("check")) { - index += 3; - } else if (checks[index].equals("ifcheck")) { - index += 5; - } else if (checks[index].equals("nullAllowed")) { - index += 1; } else { - System.out.println("Error: unknown keyword \"" + - checks[index] + "\""); - System.exit(0); + index = skipOneCheck(checks, index); } } } @@ -345,9 +369,7 @@ public class JniCodeEmitter { continue; } out.println(iii + "if (" + remaining + " < " + checks[index + 2] + ") {"); - if (emitExceptionCheck) { - out.println(iii + indent + "_exception = 1;"); - } + out.println(iii + indent + "_exception = 1;"); String exceptionClassName = "java/lang/IllegalArgumentException"; // If the "check" keyword was of the form // "check_<class name>", use the class name in the @@ -361,14 +383,19 @@ public class JniCodeEmitter { throw new RuntimeException("unknown exception abbreviation: " + abbr); } } - out.println(iii + indent + "jniThrowException(_env, " + - "\"" + exceptionClassName + "\", " + - "\"" + (isBuffer ? "remaining()" : "length - " + offset) + " < " + checks[index + 2] + "\");"); + out.println(iii + indent + + "_exceptionType = \""+exceptionClassName+"\";"); + out.println(iii + indent + + "_exceptionMessage = \"" + + (isBuffer ? "remaining()" : "length - " + + offset) + " < " + checks[index + 2] + + " < needed\";"); out.println(iii + indent + "goto exit;"); - needsExit = true; out.println(iii + "}"); + needsExit = true; + index += 3; } else if (checks[index].equals("ifcheck")) { String[] matches = checks[index + 4].split(","); @@ -388,21 +415,8 @@ public class JniCodeEmitter { lastWasIfcheck = true; index += 5; - } else if (checks[index].equals("return")) { - // ignore - index += 2; - } else if (checks[index].equals("unsupported")) { - // ignore - index += 1; - } else if (checks[index].equals("requires")) { - // ignore - index += 2; - } else if (checks[index].equals("nullAllowed")) { - // ignore - index += 1; } else { - System.out.println("Error: unknown keyword \"" + checks[index] + "\""); - System.exit(0); + index = skipOneCheck(checks, index); } } } @@ -412,6 +426,69 @@ public class JniCodeEmitter { } } + void emitSentinelCheck(CFunc cfunc, String cname, PrintStream out, + boolean isBuffer, boolean emitExceptionCheck, String offset, String remaining, String iii) { + + String[] checks = mChecker.getChecks(cfunc.getName()); + + int index = 1; + if (checks != null) { + while (index < checks.length) { + if (checks[index].startsWith("sentinel")) { + if (cname != null && !cname.equals(checks[index + 1])) { + index += 3; + continue; + } + + out.println(iii + cname + "_sentinel = false;"); + out.println(iii + "for (int i = " + remaining + + " - 1; i >= 0; i--) {"); + out.println(iii + indent + "if (" + cname + + "[i] == " + checks[index + 2] + "){"); + out.println(iii + indent + indent + + cname + "_sentinel = true;"); + out.println(iii + indent + indent + "break;"); + out.println(iii + indent + "}"); + out.println(iii + "}"); + out.println(iii + + "if (" + cname + "_sentinel == false) {"); + out.println(iii + indent + "_exception = 1;"); + out.println(iii + indent + + "_exceptionType = \"java/lang/IllegalArgumentException\";"); + out.println(iii + indent + "_exceptionMessage = \"" + cname + + " must contain " + checks[index + 2] + "!\";"); + out.println(iii + indent + "goto exit;"); + out.println(iii + "}"); + + needsExit = true; + index += 3; + } else { + index = skipOneCheck(checks, index); + } + } + } + } + + void emitLocalVariablesForSentinel(CFunc cfunc, PrintStream out) { + + String[] checks = mChecker.getChecks(cfunc.getName()); + + int index = 1; + if (checks != null) { + while (index < checks.length) { + if (checks[index].startsWith("sentinel")) { + String cname = checks[index + 1]; + out.println(indent + "bool " + cname + "_sentinel = false;"); + + index += 3; + + } else { + index = skipOneCheck(checks, index); + } + } + } + } + boolean hasNonConstArg(JFunc jfunc, CFunc cfunc, List<Integer> nonPrimitiveArgs) { if (nonPrimitiveArgs.size() > 0) { for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { @@ -638,7 +715,7 @@ public class JniCodeEmitter { return "j" + baseType; } } else if (jType.isArray()) { - return "j" + baseType + "Array"; + return jType.isClass() ? "jobjectArray" : "j" + baseType + "Array"; } else { return "jobject"; } @@ -698,8 +775,10 @@ public class JniCodeEmitter { // Append signature to function name String sig = getJniMangledName(signature).replace('.', '_').replace('/', '_'); - out.print("__" + sig); - outName += "__" + sig; + if (!mUseSimpleMethodNames) { + out.print("__" + sig); + outName += "__" + sig; + } signature = signature.replace('.', '/'); rsignature = rsignature.replace('.', '/'); @@ -734,11 +813,11 @@ public class JniCodeEmitter { for (int i = 0; i < numArgs; i++) { out.print(", "); JType argType = jfunc.getArgType(i); - String suffix; + String suffix = ""; if (!argType.isPrimitive()) { if (argType.isArray()) { suffix = "_ref"; - } else { + } else if (argType.isBuffer()) { suffix = "_buf"; } nonPrimitiveArgs.add(new Integer(i)); @@ -748,9 +827,8 @@ public class JniCodeEmitter { bufferArgNames.add(cname); numBufferArgs++; } - } else { - suffix = ""; } + if (argType.isString()) { stringArgs.add(new Integer(i)); } @@ -801,7 +879,14 @@ public class JniCodeEmitter { " \"" + cfunc.getName() + "\");"); if (!isVoid) { String retval = getErrorReturnValue(cfunc); - out.println(indent + "return " + retval + ";"); + if (cfunc.getType().isEGLHandle()) { + String baseType = cfunc.getType().getBaseType().toLowerCase(); + out.println(indent + + "return toEGLHandle(_env, " + baseType + "Class, " + + baseType + "Constructor, " + retval + ");"); + } else { + out.println(indent + "return " + retval + ";"); + } } out.println("}"); out.println(); @@ -820,7 +905,14 @@ public class JniCodeEmitter { out.println(indent + indent + " return;"); } else { String retval = getErrorReturnValue(cfunc); - out.println(indent + indent + " return " + retval + ";"); + if (cfunc.getType().isEGLHandle()) { + String baseType = cfunc.getType().getBaseType().toLowerCase(); + out.println(indent + + "return toEGLHandle(_env, " + baseType + "Class, " + + baseType + "Constructor, " + retval + ");"); + } else { + out.println(indent + "return " + retval + ";"); + } } out.println(indent + "}"); } @@ -830,23 +922,30 @@ public class JniCodeEmitter { } boolean initializeReturnValue = stringArgs.size() > 0; - - boolean emitExceptionCheck = (numArrays > 0 || numBuffers > 0 || numStrings > 0) && - hasNonConstArg(jfunc, cfunc, nonPrimitiveArgs); + boolean emitExceptionCheck = ((numArrays > 0 || numStrings > 0) + && (hasNonConstArg(jfunc, cfunc, nonPrimitiveArgs) + || (cfunc.hasPointerArg() && numArrays > 0)) + || hasCheckTest(cfunc) + || hasIfTest(cfunc)) + || (stringArgs.size() > 0); // mChecker.getChecks(cfunc.getName()) != null - // Emit an _exeption variable if there will be error checks if (emitExceptionCheck) { out.println(indent + "jint _exception = 0;"); + out.println(indent + "const char * _exceptionType;"); + out.println(indent + "const char * _exceptionMessage;"); } // Emit a single _array or multiple _XXXArray variables if (numBufferArgs == 1) { out.println(indent + "jarray _array = (jarray) 0;"); + out.println(indent + "jint _bufferOffset = (jint) 0;"); } else { for (int i = 0; i < numBufferArgs; i++) { out.println(indent + "jarray _" + bufferArgNames.get(i) + "Array = (jarray) 0;"); + out.println(indent + "jint _" + bufferArgNames.get(i) + + "BufferOffset = (jint) 0;"); } } if (!isVoid) { @@ -856,13 +955,49 @@ public class JniCodeEmitter { " _returnValue = " + retval + ";"); } else if (initializeReturnValue) { out.println(indent + returnType.getDeclaration() + - " _returnValue = 0;"); + " _returnValue = 0;"); } else { out.println(indent + returnType.getDeclaration() + " _returnValue;"); } } + // Emit local variable declarations for EGL Handles + // + // Example: + // + // EGLSurface surface_native = (EGLHandle)fromEGLHandle(_env, surfaceClass, surfaceConstructor, surface); + // + if (nonPrimitiveArgs.size() > 0) { + for (int i = 0; i < nonPrimitiveArgs.size(); i++) { + int idx = nonPrimitiveArgs.get(i).intValue(); + int cIndex = jfunc.getArgCIndex(idx); + String cname = cfunc.getArgName(cIndex); + + if (jfunc.getArgType(idx).isBuffer() + || jfunc.getArgType(idx).isArray() + || !jfunc.getArgType(idx).isEGLHandle()) + continue; + + CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); + String decl = type.getDeclaration(); + out.println(indent + + decl + " " + cname + "_native = (" + + decl + ") fromEGLHandle(_env, " + + type.getBaseType().toLowerCase() + + "GetHandleID, " + jfunc.getArgName(idx) + + ");"); + } + } + + // Emit local variable declarations for element/sentinel checks + // + // Example: + // + // bool attrib_list_sentinel_found = false; + // + emitLocalVariablesForSentinel(cfunc, out); + // Emit local variable declarations for pointer arguments // // Example: @@ -878,9 +1013,12 @@ public class JniCodeEmitter { int cIndex = jfunc.getArgCIndex(idx); String cname = cfunc.getArgName(cIndex); + if (!jfunc.getArgType(idx).isBuffer() && !jfunc.getArgType(idx).isArray()) + continue; + CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); String decl = type.getDeclaration(); - if (jfunc.getArgType(idx).isArray()) { + if (jfunc.getArgType(idx).isArray() && !jfunc.getArgType(idx).isClass()) { out.println(indent + decl + (decl.endsWith("*") ? "" : " ") + @@ -892,10 +1030,10 @@ public class JniCodeEmitter { out.println(indent + "jint " + remaining + ";"); out.println(indent + - decl + - (decl.endsWith("*") ? "" : " ") + - jfunc.getArgName(idx) + - " = (" + decl + ") 0;"); + decl + + (decl.endsWith("*") ? "" : " ") + + jfunc.getArgName(idx) + + " = (" + decl + ") 0;"); } out.println(); @@ -923,11 +1061,13 @@ public class JniCodeEmitter { CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); String decl = type.getDeclaration(); - out.println(indent + "if (!" + cname + ") {"); - out.println(indent + " jniThrowException(_env, " + - "\"java/lang/IllegalArgumentException\", \"" + cname + " == null\");"); - out.println(indent + " goto exit;"); needsExit = true; + out.println(indent + "if (!" + cname + ") {"); + out.println(indent + indent + + "_exceptionType = \"java/lang/IllegalArgumentException\";"); + out.println(indent + indent + + "_exceptionMessage = \"" + cname + " == null\";"); + out.println(indent + indent + "goto exit;"); out.println(indent + "}"); out.println(indent + "_native" + cname + " = _env->GetStringUTFChars(" + cname + ", 0);"); @@ -936,9 +1076,8 @@ public class JniCodeEmitter { out.println(); } - // Emit 'GetPrimitiveArrayCritical' for arrays + // Emit 'GetPrimitiveArrayCritical' for non-object arrays // Emit 'GetPointer' calls for Buffer pointers - int bufArgIdx = 0; if (nonPrimitiveArgs.size() > 0) { for (int i = 0; i < nonPrimitiveArgs.size(); i++) { int idx = nonPrimitiveArgs.get(i).intValue(); @@ -950,29 +1089,24 @@ public class JniCodeEmitter { remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : "_" + cname + "Remaining"; - if (jfunc.getArgType(idx).isArray()) { - out.println(indent + - "if (!" + - cname + - "_ref) {"); - if (emitExceptionCheck) { - out.println(indent + indent + "_exception = 1;"); - } - out.println(indent + " jniThrowException(_env, " + - "\"java/lang/IllegalArgumentException\", " + - "\"" + cname + " == null\");"); - out.println(indent + " goto exit;"); + if (jfunc.getArgType(idx).isArray() + && !jfunc.getArgType(idx).isEGLHandle()) { needsExit = true; + out.println(indent + "if (!" + cname + "_ref) {"); + out.println(indent + indent + "_exception = 1;"); + out.println(indent + indent + + "_exceptionType = \"java/lang/IllegalArgumentException\";"); + out.println(indent + indent + + "_exceptionMessage = \"" + cname +" == null\";"); + out.println(indent + indent + "goto exit;"); out.println(indent + "}"); - out.println(indent + "if (" + offset + " < 0) {"); - if (emitExceptionCheck) { - out.println(indent + indent + "_exception = 1;"); - } - out.println(indent + " jniThrowException(_env, " + - "\"java/lang/IllegalArgumentException\", \"" + offset + " < 0\");"); - out.println(indent + " goto exit;"); - needsExit = true; + out.println(indent + indent + "_exception = 1;"); + out.println(indent + indent + + "_exceptionType = \"java/lang/IllegalArgumentException\";"); + out.println(indent + indent + + "_exceptionMessage = \"" + offset +" < 0\";"); + out.println(indent + indent + "goto exit;"); out.println(indent + "}"); out.println(indent + remaining + " = " + @@ -997,12 +1131,48 @@ public class JniCodeEmitter { jfunc.getArgName(idx) + "_ref, (jboolean *)0);"); out.println(indent + - cname + " = " + cname + "_base + " + offset + - ";"); + cname + " = " + cname + "_base + " + offset + ";"); + + emitSentinelCheck(cfunc, cname, out, false, + emitExceptionCheck, offset, + remaining, indent); out.println(); - } else { + } else if (jfunc.getArgType(idx).isArray() + && jfunc.getArgType(idx).isEGLHandle()) { + needsExit = true; + out.println(indent + "if (!" + cname + "_ref) {"); + out.println(indent + indent + "_exception = 1;"); + out.println(indent + indent + + "_exceptionType = \"java/lang/IllegalArgumentException\";"); + out.println(indent + indent + "_exceptionMessage = \"" + cname +" == null\";"); + out.println(indent + indent + "goto exit;"); + out.println(indent + "}"); + out.println(indent + "if (" + offset + " < 0) {"); + out.println(indent + indent + "_exception = 1;"); + out.println(indent + indent + + "_exceptionType = \"java/lang/IllegalArgumentException\";"); + out.println(indent + indent + "_exceptionMessage = \"" + offset +" < 0\";"); + out.println(indent + indent + "goto exit;"); + out.println(indent + "}"); + + out.println(indent + remaining + " = " + + (mUseCPlusPlus ? "_env" : "(*_env)") + + "->GetArrayLength(" + + (mUseCPlusPlus ? "" : "_env, ") + + cname + "_ref) - " + offset + ";"); + emitNativeBoundsChecks(cfunc, cname, out, false, + emitExceptionCheck, + offset, remaining, " "); + out.println(indent + + jfunc.getArgName(idx) + " = new " + + cfunc.getArgType(cIndex).getBaseType() + + "["+ remaining + "];"); + out.println(); + } else if (jfunc.getArgType(idx).isBuffer()) { String array = numBufferArgs <= 1 ? "_array" : - "_" + bufferArgNames.get(bufArgIdx++) + "Array"; + "_" + cfunc.getArgName(cIndex) + "Array"; + String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" : + "_" + cfunc.getArgName(cIndex) + "BufferOffset"; boolean nullAllowed = isNullAllowed(cfunc) || isPointerFunc; if (nullAllowed) { @@ -1019,7 +1189,7 @@ public class JniCodeEmitter { cname + "_buf);"); String iii = " "; out.println(iii + indent + "if ( ! " + cname + " ) {"); - out.println(iii + iii + indent + "return;"); + out.println(iii + indent + indent + "return;"); out.println(iii + indent + "}"); } else { out.println(indent + @@ -1028,7 +1198,7 @@ public class JniCodeEmitter { cfunc.getArgType(cIndex).getDeclaration() + ")getPointer(_env, " + cname + - "_buf, &" + array + ", &" + remaining + + "_buf, &" + array + ", &" + remaining + ", &" + bufferOffset + ");"); } @@ -1043,6 +1213,33 @@ public class JniCodeEmitter { } } + // Emit 'GetPrimitiveArrayCritical' for pointers if needed + if (nonPrimitiveArgs.size() > 0) { + for (int i = 0; i < nonPrimitiveArgs.size(); i++) { + int idx = nonPrimitiveArgs.get(i).intValue(); + int cIndex = jfunc.getArgCIndex(idx); + + if(!jfunc.getArgType(idx).isBuffer() || isPointerFunc) continue; + + String cname = cfunc.getArgName(cIndex); + String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" : + "_" + cname + "BufferOffset"; + String array = numBufferArgs <= 1 ? "_array" : + "_" + cfunc.getArgName(cIndex) + "Array"; + + boolean nullAllowed = isNullAllowed(cfunc) || isPointerFunc; + if (nullAllowed) { + out.println(indent + "if (" + cname + "_buf && " + cname +" == NULL) {"); + } else { + out.println(indent + "if (" + cname +" == NULL) {"); + } + out.println(indent + indent + "char * _" + cname + "Base = (char *)_env->GetPrimitiveArrayCritical(" + array + ", (jboolean *) 0);"); + out.println(indent + indent + cname + " = (" +cfunc.getArgType(cIndex).getDeclaration() +") (_" + cname + "Base + " + bufferOffset + ");"); + out.println(indent + "}"); + } + } + + if (!isVoid) { out.print(indent + "_returnValue = "); } else { @@ -1075,18 +1272,23 @@ public class JniCodeEmitter { for (int i = 0; i < numArgs; i++) { String typecast; if (i == numArgs - 1 && isVBOPointerFunc) { - typecast = "const GLvoid *"; + typecast = "(const GLvoid *)"; } else { - typecast = cfunc.getArgType(i).getDeclaration(); + typecast = "(" + cfunc.getArgType(i).getDeclaration() + ")"; } out.print(indent + indent + - "(" + - typecast + - ")"); + typecast); + if (cfunc.getArgType(i).isConstCharPointer()) { out.print("_native"); } - out.print(cfunc.getArgName(i)); + + if (cfunc.getArgType(i).isEGLHandle() && + !cfunc.getArgType(i).isPointer()){ + out.print(cfunc.getArgName(i)+"_native"); + } else { + out.print(cfunc.getArgName(i)); + } if (i == numArgs - 1) { if (isPointerFunc) { @@ -1108,13 +1310,13 @@ public class JniCodeEmitter { needsExit = false; } - bufArgIdx = 0; + if (nonPrimitiveArgs.size() > 0) { for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { int idx = nonPrimitiveArgs.get(i).intValue(); int cIndex = jfunc.getArgCIndex(idx); - if (jfunc.getArgType(idx).isArray()) { + if (jfunc.getArgType(idx).isArray() && !jfunc.getArgType(idx).isClass()) { // If the argument is 'const', GL will not write to it. // In this case, we can use the 'JNI_ABORT' flag to avoid @@ -1130,22 +1332,21 @@ public class JniCodeEmitter { "_base,"); out.println(indent + indent + indent + (cfunc.getArgType(cIndex).isConst() ? - "JNI_ABORT" : - "_exception ? JNI_ABORT: 0") + + "JNI_ABORT" : "_exception ? JNI_ABORT: 0" ) + ");"); out.println(indent + "}"); } else if (jfunc.getArgType(idx).isBuffer()) { if (! isPointerFunc) { String array = numBufferArgs <= 1 ? "_array" : - "_" + bufferArgNames.get(bufArgIdx++) + "Array"; + "_" + cfunc.getArgName(cIndex) + "Array"; out.println(indent + "if (" + array + ") {"); out.println(indent + indent + "releasePointer(_env, " + array + ", " + cfunc.getArgName(cIndex) + ", " + (cfunc.getArgType(cIndex).isConst() ? - "JNI_FALSE" : "_exception ? JNI_FALSE :" + - " JNI_TRUE") + + "JNI_FALSE" : (emitExceptionCheck ? + "_exception ? JNI_FALSE : JNI_TRUE" : "JNI_TRUE")) + ");"); out.println(indent + "}"); } @@ -1168,9 +1369,60 @@ public class JniCodeEmitter { out.println(); } + // Copy results back to java arrays + if (nonPrimitiveArgs.size() > 0) { + for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { + int idx = nonPrimitiveArgs.get(i).intValue(); + int cIndex = jfunc.getArgCIndex(idx); + String baseType = cfunc.getArgType(cIndex).getBaseType().toLowerCase(); + if (jfunc.getArgType(idx).isArray() && jfunc.getArgType(idx).isClass()) { + remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : + "_" + cfunc.getArgName(cIndex) + "Remaining"; + offset = numArrays <= 1 ? "offset" : cfunc.getArgName(cIndex) + "Offset"; + out.println(indent + + "if (" + jfunc.getArgName(idx) + ") {"); + out.println(indent + indent + + "for (int i = 0; i < " + remaining + "; i++) {"); + out.println(indent + indent + indent + + "jobject " + cfunc.getArgName(cIndex) + + "_new = toEGLHandle(_env, " + baseType + + "Class, " + baseType + "Constructor, " + + cfunc.getArgName(cIndex) + "[i]);"); + out.println(indent + indent + indent + + (mUseCPlusPlus ? "_env" : "(*_env)") + + "->SetObjectArrayElement(" + + (mUseCPlusPlus ? "" : "_env, ") + + cfunc.getArgName(cIndex) + + "_ref, i + " + offset + ", " + + cfunc.getArgName(cIndex) + "_new);"); + out.println(indent + indent + "}"); + out.println(indent + indent + + "delete[] " + jfunc.getArgName(idx) + ";"); + out.println(indent + "}"); + } + } + } + + + // Throw exception if there is one + if (emitExceptionCheck) { + out.println(indent + "if (_exception) {"); + out.println(indent + indent + + "jniThrowException(_env, _exceptionType, _exceptionMessage);"); + out.println(indent + "}"); + + } + if (!isVoid) { - out.println(indent + "return _returnValue;"); + if (cfunc.getType().isEGLHandle()) { + String baseType = cfunc.getType().getBaseType().toLowerCase(); + out.println(indent + + "return toEGLHandle(_env, " + baseType + "Class, " + + baseType + "Constructor, _returnValue);"); + } else { + out.println(indent + "return _returnValue;"); + } } out.println("}"); diff --git a/opengl/tools/glgen/static/egl/EGLConfig.java b/opengl/tools/glgen/static/egl/EGLConfig.java new file mode 100644 index 0000000..d457c9f --- /dev/null +++ b/opengl/tools/glgen/static/egl/EGLConfig.java @@ -0,0 +1,37 @@ +/* +** +** Copyright 2012, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package android.opengl; + +/** + * Wrapper class for native EGLConfig objects. + * + */ +public class EGLConfig extends EGLObjectHandle { + private EGLConfig(int handle) { + super(handle); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + EGLConfig that = (EGLConfig) o; + return getHandle() == that.getHandle(); + } +} diff --git a/opengl/tools/glgen/static/egl/EGLContext.java b/opengl/tools/glgen/static/egl/EGLContext.java new file mode 100644 index 0000000..41b8ef1 --- /dev/null +++ b/opengl/tools/glgen/static/egl/EGLContext.java @@ -0,0 +1,37 @@ +/* +** +** Copyright 2012, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package android.opengl; + +/** + * Wrapper class for native EGLContext objects. + * + */ +public class EGLContext extends EGLObjectHandle { + private EGLContext(int handle) { + super(handle); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + EGLContext that = (EGLContext) o; + return getHandle() == that.getHandle(); + } +} diff --git a/opengl/tools/glgen/static/egl/EGLDisplay.java b/opengl/tools/glgen/static/egl/EGLDisplay.java new file mode 100644 index 0000000..17d1a64 --- /dev/null +++ b/opengl/tools/glgen/static/egl/EGLDisplay.java @@ -0,0 +1,37 @@ +/* +** +** Copyright 2012, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package android.opengl; + +/** + * Wrapper class for native EGLDisplay objects. + * + */ +public class EGLDisplay extends EGLObjectHandle { + private EGLDisplay(int handle) { + super(handle); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + EGLDisplay that = (EGLDisplay) o; + return getHandle() == that.getHandle(); + } +} diff --git a/opengl/tools/glgen/static/egl/EGLObjectHandle.java b/opengl/tools/glgen/static/egl/EGLObjectHandle.java new file mode 100644 index 0000000..d2710de --- /dev/null +++ b/opengl/tools/glgen/static/egl/EGLObjectHandle.java @@ -0,0 +1,47 @@ +/* +** +** Copyright 2012, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package android.opengl; + +/** + * Base class for wrapped EGL objects. + * + */ +public abstract class EGLObjectHandle { + private final int mHandle; + + protected EGLObjectHandle(int handle) { + mHandle = handle; + } + + /** + * Returns the native handle of the wrapped EGL object. This handle can be + * cast to the corresponding native type on the native side. + * + * For example, EGLDisplay dpy = (EGLDisplay)handle; + * + * @return the native handle of the wrapped EGL object. + */ + public int getHandle() { + return mHandle; + } + + @Override + public int hashCode() { + return getHandle(); + } +} diff --git a/opengl/tools/glgen/static/egl/EGLSurface.java b/opengl/tools/glgen/static/egl/EGLSurface.java new file mode 100644 index 0000000..65bec4f --- /dev/null +++ b/opengl/tools/glgen/static/egl/EGLSurface.java @@ -0,0 +1,37 @@ +/* +** +** Copyright 2012, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package android.opengl; + +/** + * Wrapper class for native EGLSurface objects. + * + */ +public class EGLSurface extends EGLObjectHandle { + private EGLSurface(int handle) { + super(handle); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + EGLSurface that = (EGLSurface) o; + return getHandle() == that.getHandle(); + } +} diff --git a/opengl/tools/glgen/stubs/egl/EGL14Header.java-if b/opengl/tools/glgen/stubs/egl/EGL14Header.java-if new file mode 100644 index 0000000..0c29d5c --- /dev/null +++ b/opengl/tools/glgen/stubs/egl/EGL14Header.java-if @@ -0,0 +1,151 @@ +** +** Copyright 2012, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +// This source file is automatically generated + +package android.opengl; + +import android.graphics.SurfaceTexture; +import android.view.Surface; +import android.view.SurfaceView; +import android.view.SurfaceHolder; + +/** + * EGL 1.4 + * + */ +public class EGL14 { + +public static final int EGL_DEFAULT_DISPLAY = 0; +public static EGLContext EGL_NO_CONTEXT = null; +public static EGLDisplay EGL_NO_DISPLAY = null; +public static EGLSurface EGL_NO_SURFACE = null; + +public static final int EGL_FALSE = 0; +public static final int EGL_TRUE = 1; +public static final int EGL_SUCCESS = 0x3000; +public static final int EGL_NOT_INITIALIZED = 0x3001; +public static final int EGL_BAD_ACCESS = 0x3002; +public static final int EGL_BAD_ALLOC = 0x3003; +public static final int EGL_BAD_ATTRIBUTE = 0x3004; +public static final int EGL_BAD_CONFIG = 0x3005; +public static final int EGL_BAD_CONTEXT = 0x3006; +public static final int EGL_BAD_CURRENT_SURFACE = 0x3007; +public static final int EGL_BAD_DISPLAY = 0x3008; +public static final int EGL_BAD_MATCH = 0x3009; +public static final int EGL_BAD_NATIVE_PIXMAP = 0x300A; +public static final int EGL_BAD_NATIVE_WINDOW = 0x300B; +public static final int EGL_BAD_PARAMETER = 0x300C; +public static final int EGL_BAD_SURFACE = 0x300D; +public static final int EGL_CONTEXT_LOST = 0x300E; +public static final int EGL_BUFFER_SIZE = 0x3020; +public static final int EGL_ALPHA_SIZE = 0x3021; +public static final int EGL_BLUE_SIZE = 0x3022; +public static final int EGL_GREEN_SIZE = 0x3023; +public static final int EGL_RED_SIZE = 0x3024; +public static final int EGL_DEPTH_SIZE = 0x3025; +public static final int EGL_STENCIL_SIZE = 0x3026; +public static final int EGL_CONFIG_CAVEAT = 0x3027; +public static final int EGL_CONFIG_ID = 0x3028; +public static final int EGL_LEVEL = 0x3029; +public static final int EGL_MAX_PBUFFER_HEIGHT = 0x302A; +public static final int EGL_MAX_PBUFFER_PIXELS = 0x302B; +public static final int EGL_MAX_PBUFFER_WIDTH = 0x302C; +public static final int EGL_NATIVE_RENDERABLE = 0x302D; +public static final int EGL_NATIVE_VISUAL_ID = 0x302E; +public static final int EGL_NATIVE_VISUAL_TYPE = 0x302F; +public static final int EGL_SAMPLES = 0x3031; +public static final int EGL_SAMPLE_BUFFERS = 0x3032; +public static final int EGL_SURFACE_TYPE = 0x3033; +public static final int EGL_TRANSPARENT_TYPE = 0x3034; +public static final int EGL_TRANSPARENT_BLUE_VALUE = 0x3035; +public static final int EGL_TRANSPARENT_GREEN_VALUE = 0x3036; +public static final int EGL_TRANSPARENT_RED_VALUE = 0x3037; +public static final int EGL_NONE = 0x3038; +public static final int EGL_BIND_TO_TEXTURE_RGB = 0x3039; +public static final int EGL_BIND_TO_TEXTURE_RGBA = 0x303A; +public static final int EGL_MIN_SWAP_INTERVAL = 0x303B; +public static final int EGL_MAX_SWAP_INTERVAL = 0x303C; +public static final int EGL_LUMINANCE_SIZE = 0x303D; +public static final int EGL_ALPHA_MASK_SIZE = 0x303E; +public static final int EGL_COLOR_BUFFER_TYPE = 0x303F; +public static final int EGL_RENDERABLE_TYPE = 0x3040; +public static final int EGL_MATCH_NATIVE_PIXMAP = 0x3041; +public static final int EGL_CONFORMANT = 0x3042; +public static final int EGL_SLOW_CONFIG = 0x3050; +public static final int EGL_NON_CONFORMANT_CONFIG = 0x3051; +public static final int EGL_TRANSPARENT_RGB = 0x3052; +public static final int EGL_RGB_BUFFER = 0x308E; +public static final int EGL_LUMINANCE_BUFFER = 0x308F; +public static final int EGL_NO_TEXTURE = 0x305C; +public static final int EGL_TEXTURE_RGB = 0x305D; +public static final int EGL_TEXTURE_RGBA = 0x305E; +public static final int EGL_TEXTURE_2D = 0x305F; +public static final int EGL_PBUFFER_BIT = 0x0001; +public static final int EGL_PIXMAP_BIT = 0x0002; +public static final int EGL_WINDOW_BIT = 0x0004; +public static final int EGL_VG_COLORSPACE_LINEAR_BIT = 0x0020; +public static final int EGL_VG_ALPHA_FORMAT_PRE_BIT = 0x0040; +public static final int EGL_MULTISAMPLE_RESOLVE_BOX_BIT = 0x0200; +public static final int EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400; +public static final int EGL_OPENGL_ES_BIT = 0x0001; +public static final int EGL_OPENVG_BIT = 0x0002; +public static final int EGL_OPENGL_ES2_BIT = 0x0004; +public static final int EGL_OPENGL_BIT = 0x0008; +public static final int EGL_VENDOR = 0x3053; +public static final int EGL_VERSION = 0x3054; +public static final int EGL_EXTENSIONS = 0x3055; +public static final int EGL_CLIENT_APIS = 0x308D; +public static final int EGL_HEIGHT = 0x3056; +public static final int EGL_WIDTH = 0x3057; +public static final int EGL_LARGEST_PBUFFER = 0x3058; +public static final int EGL_TEXTURE_FORMAT = 0x3080; +public static final int EGL_TEXTURE_TARGET = 0x3081; +public static final int EGL_MIPMAP_TEXTURE = 0x3082; +public static final int EGL_MIPMAP_LEVEL = 0x3083; +public static final int EGL_RENDER_BUFFER = 0x3086; +public static final int EGL_VG_COLORSPACE = 0x3087; +public static final int EGL_VG_ALPHA_FORMAT = 0x3088; +public static final int EGL_HORIZONTAL_RESOLUTION = 0x3090; +public static final int EGL_VERTICAL_RESOLUTION = 0x3091; +public static final int EGL_PIXEL_ASPECT_RATIO = 0x3092; +public static final int EGL_SWAP_BEHAVIOR = 0x3093; +public static final int EGL_MULTISAMPLE_RESOLVE = 0x3099; +public static final int EGL_BACK_BUFFER = 0x3084; +public static final int EGL_SINGLE_BUFFER = 0x3085; +public static final int EGL_VG_COLORSPACE_sRGB = 0x3089; +public static final int EGL_VG_COLORSPACE_LINEAR = 0x308A; +public static final int EGL_VG_ALPHA_FORMAT_NONPRE = 0x308B; +public static final int EGL_VG_ALPHA_FORMAT_PRE = 0x308C; +public static final int EGL_DISPLAY_SCALING = 10000; +public static final int EGL_BUFFER_PRESERVED = 0x3094; +public static final int EGL_BUFFER_DESTROYED = 0x3095; +public static final int EGL_OPENVG_IMAGE = 0x3096; +public static final int EGL_CONTEXT_CLIENT_TYPE = 0x3097; +public static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; +public static final int EGL_MULTISAMPLE_RESOLVE_DEFAULT = 0x309A; +public static final int EGL_MULTISAMPLE_RESOLVE_BOX = 0x309B; +public static final int EGL_OPENGL_ES_API = 0x30A0; +public static final int EGL_OPENVG_API = 0x30A1; +public static final int EGL_OPENGL_API = 0x30A2; +public static final int EGL_DRAW = 0x3059; +public static final int EGL_READ = 0x305A; +public static final int EGL_CORE_NATIVE_ENGINE = 0x305B; + + native private static void _nativeClassInit(); + static { + _nativeClassInit(); + } diff --git a/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp b/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp new file mode 100644 index 0000000..7904ac7 --- /dev/null +++ b/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp @@ -0,0 +1,132 @@ +** +** Copyright 2012, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +// This source file is automatically generated + +#include "jni.h" +#include "JNIHelp.h" +#include <android_runtime/AndroidRuntime.h> +#include <android_runtime/android_view_Surface.h> +#include <android_runtime/android_graphics_SurfaceTexture.h> +#include <utils/misc.h> + +#include <assert.h> +#include <EGL/egl.h> + +#include <gui/Surface.h> +#include <gui/SurfaceTexture.h> +#include <gui/SurfaceTextureClient.h> + +#include <ui/ANativeObjectBase.h> + +static int initialized = 0; + +static jclass egldisplayClass; +static jclass eglcontextClass; +static jclass eglsurfaceClass; +static jclass eglconfigClass; + +static jmethodID egldisplayGetHandleID; +static jmethodID eglcontextGetHandleID; +static jmethodID eglsurfaceGetHandleID; +static jmethodID eglconfigGetHandleID; + +static jmethodID egldisplayConstructor; +static jmethodID eglcontextConstructor; +static jmethodID eglsurfaceConstructor; +static jmethodID eglconfigConstructor; + +static jobject eglNoContextObject; +static jobject eglNoDisplayObject; +static jobject eglNoSurfaceObject; + + + +/* Cache method IDs each time the class is loaded. */ + +static void +nativeClassInit(JNIEnv *_env, jclass glImplClass) +{ + jclass egldisplayClassLocal = _env->FindClass("android/opengl/EGLDisplay"); + egldisplayClass = (jclass) _env->NewGlobalRef(egldisplayClassLocal); + jclass eglcontextClassLocal = _env->FindClass("android/opengl/EGLContext"); + eglcontextClass = (jclass) _env->NewGlobalRef(eglcontextClassLocal); + jclass eglsurfaceClassLocal = _env->FindClass("android/opengl/EGLSurface"); + eglsurfaceClass = (jclass) _env->NewGlobalRef(eglsurfaceClassLocal); + jclass eglconfigClassLocal = _env->FindClass("android/opengl/EGLConfig"); + eglconfigClass = (jclass) _env->NewGlobalRef(eglconfigClassLocal); + + egldisplayGetHandleID = _env->GetMethodID(egldisplayClass, "getHandle", "()I"); + eglcontextGetHandleID = _env->GetMethodID(eglcontextClass, "getHandle", "()I"); + eglsurfaceGetHandleID = _env->GetMethodID(eglsurfaceClass, "getHandle", "()I"); + eglconfigGetHandleID = _env->GetMethodID(eglconfigClass, "getHandle", "()I"); + + + egldisplayConstructor = _env->GetMethodID(egldisplayClass, "<init>", "(I)V"); + eglcontextConstructor = _env->GetMethodID(eglcontextClass, "<init>", "(I)V"); + eglsurfaceConstructor = _env->GetMethodID(eglsurfaceClass, "<init>", "(I)V"); + eglconfigConstructor = _env->GetMethodID(eglconfigClass, "<init>", "(I)V"); + + jobject localeglNoContextObject = _env->NewObject(eglcontextClass, eglcontextConstructor, (jint)EGL_NO_CONTEXT); + eglNoContextObject = _env->NewGlobalRef(localeglNoContextObject); + jobject localeglNoDisplayObject = _env->NewObject(egldisplayClass, egldisplayConstructor, (jint)EGL_NO_DISPLAY); + eglNoDisplayObject = _env->NewGlobalRef(localeglNoDisplayObject); + jobject localeglNoSurfaceObject = _env->NewObject(eglsurfaceClass, eglsurfaceConstructor, (jint)EGL_NO_SURFACE); + eglNoSurfaceObject = _env->NewGlobalRef(localeglNoSurfaceObject); + + + jclass eglClass = _env->FindClass("android/opengl/EGL14"); + jfieldID noContextFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_CONTEXT", "Landroid/opengl/EGLContext;"); + _env->SetStaticObjectField(eglClass, noContextFieldID, eglNoContextObject); + + jfieldID noDisplayFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_DISPLAY", "Landroid/opengl/EGLDisplay;"); + _env->SetStaticObjectField(eglClass, noDisplayFieldID, eglNoDisplayObject); + + jfieldID noSurfaceFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_SURFACE", "Landroid/opengl/EGLSurface;"); + _env->SetStaticObjectField(eglClass, noSurfaceFieldID, eglNoSurfaceObject); +} + +static void * +fromEGLHandle(JNIEnv *_env, jmethodID mid, jobject obj) { + if (obj == NULL){ + jniThrowException(_env, "java/lang/IllegalArgumentException", + "Object is set to null."); + } + + return (void*) (_env->CallIntMethod(obj, mid)); +} + +static jobject +toEGLHandle(JNIEnv *_env, jclass cls, jmethodID con, void * handle) { + if (cls == eglcontextClass && + (EGLContext)handle == EGL_NO_CONTEXT) { + return eglNoContextObject; + } + + if (cls == egldisplayClass && + (EGLDisplay)handle == EGL_NO_DISPLAY) { + return eglNoDisplayObject; + } + + if (cls == eglsurfaceClass && + (EGLSurface)handle == EGL_NO_SURFACE) { + return eglNoSurfaceObject; + } + + return _env->NewObject(cls, con, (jint)handle); +} + +// -------------------------------------------------------------------------- diff --git a/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp b/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp new file mode 100644 index 0000000..610cde5 --- /dev/null +++ b/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp @@ -0,0 +1,154 @@ +/* EGLSurface eglCreateWindowSurface ( EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list ) */ +static jobject +android_eglCreateWindowSurface + (JNIEnv *_env, jobject _this, jobject dpy, jobject config, jobject win, jintArray attrib_list_ref, jint offset) { + jint _exception = 0; + const char * _exceptionType = ""; + const char * _exceptionMessage = ""; + EGLSurface _returnValue = (EGLSurface) 0; + EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy); + EGLConfig config_native = (EGLConfig) fromEGLHandle(_env, eglconfigGetHandleID, config); + int attrib_list_sentinel = 0; + EGLint *attrib_list_base = (EGLint *) 0; + jint _remaining; + EGLint *attrib_list = (EGLint *) 0; + android::sp<ANativeWindow> window; + + if (!attrib_list_ref) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "attrib_list == null"; + goto exit; + } + if (offset < 0) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "offset < 0"; + goto exit; + } + if (win == NULL) { +not_valid_surface: + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "Make sure the SurfaceView or associated SurfaceHolder has a valid Surface"; + goto exit; + } + + window = android::android_Surface_getNativeWindow(_env, win); + + if (window == NULL) + goto not_valid_surface; + + _remaining = _env->GetArrayLength(attrib_list_ref) - offset; + attrib_list_base = (EGLint *) + _env->GetPrimitiveArrayCritical(attrib_list_ref, (jboolean *)0); + attrib_list = attrib_list_base + offset; + attrib_list_sentinel = 0; + for (int i = _remaining - 1; i >= 0; i--) { + if (*((EGLint*)(attrib_list + i)) == EGL_NONE){ + attrib_list_sentinel = 1; + break; + } + } + if (attrib_list_sentinel == 0) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "attrib_list must contain EGL_NONE!"; + goto exit; + } + + _returnValue = eglCreateWindowSurface( + (EGLDisplay)dpy_native, + (EGLConfig)config_native, + (EGLNativeWindowType)window.get(), + (EGLint *)attrib_list + ); + +exit: + if (attrib_list_base) { + _env->ReleasePrimitiveArrayCritical(attrib_list_ref, attrib_list_base, + JNI_ABORT); + } + if (_exception) { + jniThrowException(_env, _exceptionType, _exceptionMessage); + } + return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue); +} + +/* EGLSurface eglCreateWindowSurface ( EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list ) */ +static jobject +android_eglCreateWindowSurfaceTexture + (JNIEnv *_env, jobject _this, jobject dpy, jobject config, jobject win, jintArray attrib_list_ref, jint offset) { + jint _exception = 0; + const char * _exceptionType = ""; + const char * _exceptionMessage = ""; + EGLSurface _returnValue = (EGLSurface) 0; + EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy); + EGLConfig config_native = (EGLConfig) fromEGLHandle(_env, eglconfigGetHandleID, config); + int attrib_list_sentinel = 0; + EGLint *attrib_list_base = (EGLint *) 0; + jint _remaining; + EGLint *attrib_list = (EGLint *) 0; + android::sp<ANativeWindow> window; + android::sp<android::SurfaceTexture> surfaceTexture; + + if (!attrib_list_ref) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "attrib_list == null"; + goto exit; + } + if (offset < 0) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "offset < 0"; + goto exit; + } + if (win == NULL) { +not_valid_surface: + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "Make sure the SurfaceView or associated SurfaceHolder has a valid Surface"; + goto exit; + } + surfaceTexture = android::SurfaceTexture_getSurfaceTexture(_env, win); + window = new android::SurfaceTextureClient(surfaceTexture); + + if (window == NULL) + goto not_valid_surface; + + _remaining = _env->GetArrayLength(attrib_list_ref) - offset; + attrib_list_base = (EGLint *) + _env->GetPrimitiveArrayCritical(attrib_list_ref, (jboolean *)0); + attrib_list = attrib_list_base + offset; + attrib_list_sentinel = 0; + for (int i = _remaining - 1; i >= 0; i--) { + if (*((EGLint*)(attrib_list + i)) == EGL_NONE){ + attrib_list_sentinel = 1; + break; + } + } + if (attrib_list_sentinel == 0) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "attrib_list must contain EGL_NONE!"; + goto exit; + } + + _returnValue = eglCreateWindowSurface( + (EGLDisplay)dpy_native, + (EGLConfig)config_native, + (EGLNativeWindowType)window.get(), + (EGLint *)attrib_list + ); + +exit: + if (attrib_list_base) { + _env->ReleasePrimitiveArrayCritical(attrib_list_ref, attrib_list_base, + JNI_ABORT); + } + if (_exception) { + jniThrowException(_env, _exceptionType, _exceptionMessage); + } + return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue); +} diff --git a/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.java b/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.java new file mode 100644 index 0000000..e42334e --- /dev/null +++ b/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.java @@ -0,0 +1,48 @@ + // C function EGLSurface eglCreateWindowSurface ( EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list ) + + private static native EGLSurface _eglCreateWindowSurface( + EGLDisplay dpy, + EGLConfig config, + Object win, + int[] attrib_list, + int offset + ); + + private static native EGLSurface _eglCreateWindowSurfaceTexture( + EGLDisplay dpy, + EGLConfig config, + Object win, + int[] attrib_list, + int offset + ); + + public static EGLSurface eglCreateWindowSurface(EGLDisplay dpy, + EGLConfig config, + Object win, + int[] attrib_list, + int offset + ){ + Surface sur = null; + if (win instanceof SurfaceView) { + SurfaceView surfaceView = (SurfaceView)win; + sur = surfaceView.getHolder().getSurface(); + } else if (win instanceof SurfaceHolder) { + SurfaceHolder holder = (SurfaceHolder)win; + sur = holder.getSurface(); + } + + EGLSurface surface; + if (sur != null) { + surface = _eglCreateWindowSurface(dpy, config, sur, attrib_list, offset); + } else if (win instanceof SurfaceTexture) { + surface = _eglCreateWindowSurfaceTexture(dpy, config, + win, attrib_list, offset); + } else { + throw new java.lang.UnsupportedOperationException( + "eglCreateWindowSurface() can only be called with an instance of " + + "SurfaceView, SurfaceTexture or SurfaceHolder at the moment, " + + "this will be fixed later."); + } + + return surface; + } diff --git a/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.nativeReg b/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.nativeReg new file mode 100644 index 0000000..c37d05b --- /dev/null +++ b/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.nativeReg @@ -0,0 +1,2 @@ +{"_eglCreateWindowSurface", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLConfig;Ljava/lang/Object;[II)Landroid/opengl/EGLSurface;", (void *) android_eglCreateWindowSurface }, +{"_eglCreateWindowSurfaceTexture", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLConfig;Ljava/lang/Object;[II)Landroid/opengl/EGLSurface;", (void *) android_eglCreateWindowSurfaceTexture }, diff --git a/opengl/tools/glgen/stubs/egl/eglQueryString.cpp b/opengl/tools/glgen/stubs/egl/eglQueryString.cpp new file mode 100644 index 0000000..625dad7 --- /dev/null +++ b/opengl/tools/glgen/stubs/egl/eglQueryString.cpp @@ -0,0 +1,10 @@ +/* const char * eglQueryString ( EGLDisplay dpy, EGLint name ) */ +static jstring +android_eglQueryString__Landroind_opengl_EGLDisplay_2I + (JNIEnv *_env, jobject _this, jobject dpy, jint name) { + const char* chars = (const char*) eglQueryString( + (EGLDisplay)fromEGLHandle(_env, egldisplayGetHandleID, dpy), + (EGLint)name + ); + return _env->NewStringUTF(chars); +} diff --git a/opengl/tools/glgen/stubs/egl/eglQueryString.java b/opengl/tools/glgen/stubs/egl/eglQueryString.java new file mode 100644 index 0000000..f5d5a38 --- /dev/null +++ b/opengl/tools/glgen/stubs/egl/eglQueryString.java @@ -0,0 +1,6 @@ + // C function const char * eglQueryString ( EGLDisplay dpy, EGLint name ) + + public static native String eglQueryString( + EGLDisplay dpy, + int name + ); diff --git a/opengl/tools/glgen/stubs/egl/eglQueryString.nativeReg b/opengl/tools/glgen/stubs/egl/eglQueryString.nativeReg new file mode 100644 index 0000000..8276cdb --- /dev/null +++ b/opengl/tools/glgen/stubs/egl/eglQueryString.nativeReg @@ -0,0 +1 @@ +{"eglQueryString", "(Landroid/opengl/EGLDisplay;I)Ljava/lang/String;", (void *) android_eglQueryString__Landroind_opengl_EGLDisplay_2I },
diff --git a/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp index 5d418d7..172c0e7 100644 --- a/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp +++ b/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp @@ -62,14 +62,12 @@ nativeClassInit(JNIEnv *_env, jclass glImplClass) static void * -getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining) +getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *offset) { jint position; jint limit; jint elementSizeShift; jlong pointer; - jint offset; - void *data; position = _env->GetIntField(buffer, positionID); limit = _env->GetIntField(buffer, limitID); @@ -84,11 +82,10 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining) *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass, getBaseArrayID, buffer); - offset = _env->CallStaticIntMethod(nioAccessClass, + *offset = _env->CallStaticIntMethod(nioAccessClass, getBaseArrayOffsetID, buffer); - data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0); - return (void *) ((char *) data + offset); + return NULL; } diff --git a/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp index 35a3c33..4ef815b 100644 --- a/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp +++ b/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp @@ -74,14 +74,12 @@ nativeClassInit(JNIEnv *_env, jclass glImplClass) } static void * -getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining) +getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *offset) { jint position; jint limit; jint elementSizeShift; jlong pointer; - jint offset; - void *data; position = _env->GetIntField(buffer, positionID); limit = _env->GetIntField(buffer, limitID); @@ -96,11 +94,10 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining) *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass, getBaseArrayID, buffer); - offset = _env->CallStaticIntMethod(nioAccessClass, + *offset = _env->CallStaticIntMethod(nioAccessClass, getBaseArrayOffsetID, buffer); - data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0); - return (void *) ((char *) data + offset); + return NULL; } static void diff --git a/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp index 9b29a44..0df95f4 100644 --- a/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp +++ b/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp @@ -71,14 +71,12 @@ nativeClassInit(JNIEnv *_env, jclass glImplClass) static void * -getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining) +getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *offset) { jint position; jint limit; jint elementSizeShift; jlong pointer; - jint offset; - void *data; position = _env->GetIntField(buffer, positionID); limit = _env->GetIntField(buffer, limitID); @@ -93,11 +91,9 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining) *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass, getBaseArrayID, buffer); - offset = _env->CallStaticIntMethod(nioAccessClass, + *offset = _env->CallStaticIntMethod(nioAccessClass, getBaseArrayOffsetID, buffer); - data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0); - - return (void *) ((char *) data + offset); + return NULL; } diff --git a/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp index 823079f..dd860d5 100644 --- a/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp +++ b/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp @@ -69,14 +69,12 @@ nativeClassInit(JNIEnv *_env, jclass glImplClass) static void * -getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining) +getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *offset) { jint position; jint limit; jint elementSizeShift; jlong pointer; - jint offset; - void *data; position = _env->GetIntField(buffer, positionID); limit = _env->GetIntField(buffer, limitID); @@ -91,11 +89,10 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining) *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass, getBaseArrayID, buffer); - offset = _env->CallStaticIntMethod(nioAccessClass, + *offset = _env->CallStaticIntMethod(nioAccessClass, getBaseArrayOffsetID, buffer); - data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0); - return (void *) ((char *) data + offset); + return NULL; } diff --git a/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp index 13a2577..996f441 100644 --- a/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp +++ b/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp @@ -62,14 +62,12 @@ nativeClassInit(JNIEnv *_env, jclass glImplClass) static void * -getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining) +getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *offset) { jint position; jint limit; jint elementSizeShift; jlong pointer; - jint offset; - void *data; position = _env->GetIntField(buffer, positionID); limit = _env->GetIntField(buffer, limitID); @@ -84,11 +82,10 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining) *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass, getBaseArrayID, buffer); - offset = _env->CallStaticIntMethod(nioAccessClass, + *offset = _env->CallStaticIntMethod(nioAccessClass, getBaseArrayOffsetID, buffer); - data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0); - return (void *) ((char *) data + offset); + return NULL; } diff --git a/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.cpp b/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.cpp new file mode 100644 index 0000000..27b91fc --- /dev/null +++ b/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.cpp @@ -0,0 +1,328 @@ +/* void glGetActiveAttrib ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) */ +static void +android_glGetActiveAttrib__III_3II_3II_3II_3BI + (JNIEnv *_env, jobject _this, jint program, jint index, jint bufsize, jintArray length_ref, jint lengthOffset, jintArray size_ref, jint sizeOffset, jintArray type_ref, jint typeOffset, jbyteArray name_ref, jint nameOffset) { + jint _exception = 0; + const char * _exceptionType; + const char * _exceptionMessage; + GLsizei *length_base = (GLsizei *) 0; + jint _lengthRemaining; + GLsizei *length = (GLsizei *) 0; + GLint *size_base = (GLint *) 0; + jint _sizeRemaining; + GLint *size = (GLint *) 0; + GLenum *type_base = (GLenum *) 0; + jint _typeRemaining; + GLenum *type = (GLenum *) 0; + char *name_base = (char *) 0; + jint _nameRemaining; + char *name = (char *) 0; + + if (!length_ref) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "length == null"; + goto exit; + } + if (lengthOffset < 0) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "lengthOffset < 0"; + goto exit; + } + _lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset; + length_base = (GLsizei *) + _env->GetPrimitiveArrayCritical(length_ref, (jboolean *)0); + length = length_base + lengthOffset; + + if (!size_ref) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "size == null"; + goto exit; + } + if (sizeOffset < 0) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "sizeOffset < 0"; + goto exit; + } + _sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset; + size_base = (GLint *) + _env->GetPrimitiveArrayCritical(size_ref, (jboolean *)0); + size = size_base + sizeOffset; + + if (!type_ref) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "type == null"; + goto exit; + } + if (typeOffset < 0) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "typeOffset < 0"; + goto exit; + } + _typeRemaining = _env->GetArrayLength(type_ref) - typeOffset; + type_base = (GLenum *) + _env->GetPrimitiveArrayCritical(type_ref, (jboolean *)0); + type = type_base + typeOffset; + + if (!name_ref) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "name == null"; + goto exit; + } + if (nameOffset < 0) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "nameOffset < 0"; + goto exit; + } + _nameRemaining = _env->GetArrayLength(name_ref) - nameOffset; + name_base = (char *) + _env->GetPrimitiveArrayCritical(name_ref, (jboolean *)0); + name = name_base + nameOffset; + + glGetActiveAttrib( + (GLuint)program, + (GLuint)index, + (GLsizei)bufsize, + (GLsizei *)length, + (GLint *)size, + (GLenum *)type, + (char *)name + ); + +exit: + if (name_base) { + _env->ReleasePrimitiveArrayCritical(name_ref, name_base, + _exception ? JNI_ABORT: 0); + } + if (type_base) { + _env->ReleasePrimitiveArrayCritical(type_ref, type_base, + _exception ? JNI_ABORT: 0); + } + if (size_base) { + _env->ReleasePrimitiveArrayCritical(size_ref, size_base, + _exception ? JNI_ABORT: 0); + } + if (length_base) { + _env->ReleasePrimitiveArrayCritical(length_ref, length_base, + _exception ? JNI_ABORT: 0); + } + if (_exception) { + jniThrowException(_env, _exceptionType, _exceptionMessage); + } +} + +/* void glGetActiveAttrib ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) */ +static void +android_glGetActiveAttrib__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2B + (JNIEnv *_env, jobject _this, jint program, jint index, jint bufsize, jobject length_buf, jobject size_buf, jobject type_buf, jbyte name) { + jarray _lengthArray = (jarray) 0; + jint _lengthBufferOffset = (jint) 0; + jarray _sizeArray = (jarray) 0; + jint _sizeBufferOffset = (jint) 0; + jarray _typeArray = (jarray) 0; + jint _typeBufferOffset = (jint) 0; + jint _lengthRemaining; + GLsizei *length = (GLsizei *) 0; + jint _sizeRemaining; + GLint *size = (GLint *) 0; + jint _typeRemaining; + GLenum *type = (GLenum *) 0; + + length = (GLsizei *)getPointer(_env, length_buf, &_lengthArray, &_lengthRemaining, &_lengthBufferOffset); + size = (GLint *)getPointer(_env, size_buf, &_sizeArray, &_sizeRemaining, &_sizeBufferOffset); + type = (GLenum *)getPointer(_env, type_buf, &_typeArray, &_typeRemaining, &_typeBufferOffset); + if (length == NULL) { + char * _lengthBase = (char *)_env->GetPrimitiveArrayCritical(_lengthArray, (jboolean *) 0); + length = (GLsizei *) (_lengthBase + _lengthBufferOffset); + } + if (size == NULL) { + char * _sizeBase = (char *)_env->GetPrimitiveArrayCritical(_sizeArray, (jboolean *) 0); + size = (GLint *) (_sizeBase + _sizeBufferOffset); + } + if (type == NULL) { + char * _typeBase = (char *)_env->GetPrimitiveArrayCritical(_typeArray, (jboolean *) 0); + type = (GLenum *) (_typeBase + _typeBufferOffset); + } + glGetActiveAttrib( + (GLuint)program, + (GLuint)index, + (GLsizei)bufsize, + (GLsizei *)length, + (GLint *)size, + (GLenum *)type, + (char *)name + ); + if (_typeArray) { + releasePointer(_env, _typeArray, type, JNI_TRUE); + } + if (_sizeArray) { + releasePointer(_env, _sizeArray, size, JNI_TRUE); + } + if (_lengthArray) { + releasePointer(_env, _lengthArray, length, JNI_TRUE); + } +} + +/* void glGetActiveAttrib ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) */ +static jstring +android_glGetActiveAttrib1 + (JNIEnv *_env, jobject _this, jint program, jint index, jintArray size_ref, jint sizeOffset, jintArray type_ref, jint typeOffset) { + jint _exception = 0; + const char * _exceptionType; + const char * _exceptionMessage; + GLint *size_base = (GLint *) 0; + jint _sizeRemaining; + GLint *size = (GLint *) 0; + GLenum *type_base = (GLenum *) 0; + jint _typeRemaining; + GLenum *type = (GLenum *) 0; + + jstring result = 0; + + GLint len = 0; + glGetProgramiv((GLuint)program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &len); + if (!len) { + return _env->NewStringUTF(""); + } + char* buf = (char*) malloc(len); + + if (buf == NULL) { + jniThrowException(_env, "java/lang/IllegalArgumentException", "out of memory"); + return NULL; + } + if (!size_ref) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "size == null"; + goto exit; + } + if (sizeOffset < 0) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "sizeOffset < 0"; + goto exit; + } + _sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset; + size_base = (GLint *) + _env->GetPrimitiveArrayCritical(size_ref, (jboolean *)0); + size = size_base + sizeOffset; + + if (!type_ref) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "type == null"; + goto exit; + } + if (typeOffset < 0) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "typeOffset < 0"; + goto exit; + } + _typeRemaining = _env->GetArrayLength(type_ref) - typeOffset; + type_base = (GLenum *) + _env->GetPrimitiveArrayCritical(type_ref, (jboolean *)0); + type = type_base + typeOffset; + + glGetActiveAttrib( + (GLuint)program, + (GLuint)index, + (GLsizei)len, + NULL, + (GLint *)size, + (GLenum *)type, + (char *)buf + ); +exit: + if (type_base) { + _env->ReleasePrimitiveArrayCritical(type_ref, type_base, + _exception ? JNI_ABORT: 0); + } + if (size_base) { + _env->ReleasePrimitiveArrayCritical(size_ref, size_base, + _exception ? JNI_ABORT: 0); + } + if (_exception != 1) { + result = _env->NewStringUTF(buf); + } + if (buf) { + free(buf); + } + if (_exception) { + jniThrowException(_env, _exceptionType, _exceptionMessage); + } + if (result == 0) { + result = _env->NewStringUTF(""); + } + + return result; +} + +/* void glGetActiveAttrib ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) */ +static jstring +android_glGetActiveAttrib2 + (JNIEnv *_env, jobject _this, jint program, jint index, jobject size_buf, jobject type_buf) { + jarray _sizeArray = (jarray) 0; + jint _sizeBufferOffset = (jint) 0; + jarray _typeArray = (jarray) 0; + jint _typeBufferOffset = (jint) 0; + jint _lengthRemaining; + GLsizei *length = (GLsizei *) 0; + jint _sizeRemaining; + GLint *size = (GLint *) 0; + jint _typeRemaining; + GLenum *type = (GLenum *) 0; + + jstring result = 0; + + GLint len = 0; + glGetProgramiv((GLuint)program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &len); + if (!len) { + return _env->NewStringUTF(""); + } + char* buf = (char*) malloc(len); + + if (buf == NULL) { + jniThrowException(_env, "java/lang/IllegalArgumentException", "out of memory"); + return NULL; + } + + size = (GLint *)getPointer(_env, size_buf, &_sizeArray, &_sizeRemaining, &_sizeBufferOffset); + type = (GLenum *)getPointer(_env, type_buf, &_typeArray, &_typeRemaining, &_typeBufferOffset); + if (size == NULL) { + char * _sizeBase = (char *)_env->GetPrimitiveArrayCritical(_sizeArray, (jboolean *) 0); + size = (GLint *) (_sizeBase + _sizeBufferOffset); + } + if (type == NULL) { + char * _typeBase = (char *)_env->GetPrimitiveArrayCritical(_typeArray, (jboolean *) 0); + type = (GLenum *) (_typeBase + _typeBufferOffset); + } + glGetActiveAttrib( + (GLuint)program, + (GLuint)index, + (GLsizei)len, + NULL, + (GLint *)size, + (GLenum *)type, + (char *)buf + ); + + if (_typeArray) { + releasePointer(_env, _typeArray, type, JNI_TRUE); + } + if (_sizeArray) { + releasePointer(_env, _sizeArray, size, JNI_TRUE); + } + result = _env->NewStringUTF(buf); + if (buf) { + free(buf); + } + return result; +} diff --git a/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.java b/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.java new file mode 100644 index 0000000..bad2137 --- /dev/null +++ b/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.java @@ -0,0 +1,47 @@ + // C function void glGetActiveAttrib ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) + + public static native void glGetActiveAttrib( + int program, + int index, + int bufsize, + int[] length, + int lengthOffset, + int[] size, + int sizeOffset, + int[] type, + int typeOffset, + byte[] name, + int nameOffset + ); + + // C function void glGetActiveAttrib ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) + + public static native void glGetActiveAttrib( + int program, + int index, + int bufsize, + java.nio.IntBuffer length, + java.nio.IntBuffer size, + java.nio.IntBuffer type, + byte name + ); + + // C function void glGetActiveAttrib ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) + + public static native String glGetActiveAttrib( + int program, + int index, + int[] size, + int sizeOffset, + int[] type, + int typeOffset + ); + + // C function void glGetActiveAttrib ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) + + public static native String glGetActiveAttrib( + int program, + int index, + java.nio.IntBuffer size, + java.nio.IntBuffer type + ); diff --git a/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.nativeReg b/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.nativeReg new file mode 100644 index 0000000..f54c0a0 --- /dev/null +++ b/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.nativeReg @@ -0,0 +1,4 @@ +{"glGetActiveAttrib", "(III[II[II[II[BI)V", (void *) android_glGetActiveAttrib__III_3II_3II_3II_3BI }, +{"glGetActiveAttrib", "(IIILjava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;B)V", (void *) android_glGetActiveAttrib__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2B }, +{"glGetActiveAttrib", "(II[II[II)Ljava/lang/String;", (void *) android_glGetActiveAttrib1 }, +{"glGetActiveAttrib", "(IILjava/nio/IntBuffer;Ljava/nio/IntBuffer;)Ljava/lang/String;", (void *) android_glGetActiveAttrib2 }, diff --git a/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.cpp b/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.cpp new file mode 100644 index 0000000..58f704c --- /dev/null +++ b/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.cpp @@ -0,0 +1,329 @@ +/* void glGetActiveUniform ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) */ +static void +android_glGetActiveUniform__III_3II_3II_3II_3BI + (JNIEnv *_env, jobject _this, jint program, jint index, jint bufsize, jintArray length_ref, jint lengthOffset, jintArray size_ref, jint sizeOffset, jintArray type_ref, jint typeOffset, jbyteArray name_ref, jint nameOffset) { + jint _exception = 0; + const char * _exceptionType; + const char * _exceptionMessage; + GLsizei *length_base = (GLsizei *) 0; + jint _lengthRemaining; + GLsizei *length = (GLsizei *) 0; + GLint *size_base = (GLint *) 0; + jint _sizeRemaining; + GLint *size = (GLint *) 0; + GLenum *type_base = (GLenum *) 0; + jint _typeRemaining; + GLenum *type = (GLenum *) 0; + char *name_base = (char *) 0; + jint _nameRemaining; + char *name = (char *) 0; + + if (!length_ref) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "length == null"; + goto exit; + } + if (lengthOffset < 0) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "lengthOffset < 0"; + goto exit; + } + _lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset; + length_base = (GLsizei *) + _env->GetPrimitiveArrayCritical(length_ref, (jboolean *)0); + length = length_base + lengthOffset; + + if (!size_ref) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "size == null"; + goto exit; + } + if (sizeOffset < 0) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "sizeOffset < 0"; + goto exit; + } + _sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset; + size_base = (GLint *) + _env->GetPrimitiveArrayCritical(size_ref, (jboolean *)0); + size = size_base + sizeOffset; + + if (!type_ref) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "type == null"; + goto exit; + } + if (typeOffset < 0) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "typeOffset < 0"; + goto exit; + } + _typeRemaining = _env->GetArrayLength(type_ref) - typeOffset; + type_base = (GLenum *) + _env->GetPrimitiveArrayCritical(type_ref, (jboolean *)0); + type = type_base + typeOffset; + + if (!name_ref) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "name == null"; + goto exit; + } + if (nameOffset < 0) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "nameOffset < 0"; + goto exit; + } + _nameRemaining = _env->GetArrayLength(name_ref) - nameOffset; + name_base = (char *) + _env->GetPrimitiveArrayCritical(name_ref, (jboolean *)0); + name = name_base + nameOffset; + + glGetActiveUniform( + (GLuint)program, + (GLuint)index, + (GLsizei)bufsize, + (GLsizei *)length, + (GLint *)size, + (GLenum *)type, + (char *)name + ); + +exit: + if (name_base) { + _env->ReleasePrimitiveArrayCritical(name_ref, name_base, + _exception ? JNI_ABORT: 0); + } + if (type_base) { + _env->ReleasePrimitiveArrayCritical(type_ref, type_base, + _exception ? JNI_ABORT: 0); + } + if (size_base) { + _env->ReleasePrimitiveArrayCritical(size_ref, size_base, + _exception ? JNI_ABORT: 0); + } + if (length_base) { + _env->ReleasePrimitiveArrayCritical(length_ref, length_base, + _exception ? JNI_ABORT: 0); + } + if (_exception) { + jniThrowException(_env, _exceptionType, _exceptionMessage); + } +} + +/* void glGetActiveUniform ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) */ +static void +android_glGetActiveUniform__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2B + (JNIEnv *_env, jobject _this, jint program, jint index, jint bufsize, jobject length_buf, jobject size_buf, jobject type_buf, jbyte name) { + jarray _lengthArray = (jarray) 0; + jint _lengthBufferOffset = (jint) 0; + jarray _sizeArray = (jarray) 0; + jint _sizeBufferOffset = (jint) 0; + jarray _typeArray = (jarray) 0; + jint _typeBufferOffset = (jint) 0; + jint _lengthRemaining; + GLsizei *length = (GLsizei *) 0; + jint _sizeRemaining; + GLint *size = (GLint *) 0; + jint _typeRemaining; + GLenum *type = (GLenum *) 0; + + length = (GLsizei *)getPointer(_env, length_buf, &_lengthArray, &_lengthRemaining, &_lengthBufferOffset); + size = (GLint *)getPointer(_env, size_buf, &_sizeArray, &_sizeRemaining, &_sizeBufferOffset); + type = (GLenum *)getPointer(_env, type_buf, &_typeArray, &_typeRemaining, &_typeBufferOffset); + if (length == NULL) { + char * _lengthBase = (char *)_env->GetPrimitiveArrayCritical(_lengthArray, (jboolean *) 0); + length = (GLsizei *) (_lengthBase + _lengthBufferOffset); + } + if (size == NULL) { + char * _sizeBase = (char *)_env->GetPrimitiveArrayCritical(_sizeArray, (jboolean *) 0); + size = (GLint *) (_sizeBase + _sizeBufferOffset); + } + if (type == NULL) { + char * _typeBase = (char *)_env->GetPrimitiveArrayCritical(_typeArray, (jboolean *) 0); + type = (GLenum *) (_typeBase + _typeBufferOffset); + } + glGetActiveUniform( + (GLuint)program, + (GLuint)index, + (GLsizei)bufsize, + (GLsizei *)length, + (GLint *)size, + (GLenum *)type, + (char *)name + ); + if (_typeArray) { + releasePointer(_env, _typeArray, type, JNI_TRUE); + } + if (_sizeArray) { + releasePointer(_env, _sizeArray, size, JNI_TRUE); + } + if (_lengthArray) { + releasePointer(_env, _lengthArray, length, JNI_TRUE); + } +} + +/* void glGetActiveUniform ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) */ +static jstring +android_glGetActiveUniform1 + (JNIEnv *_env, jobject _this, jint program, jint index, jintArray size_ref, jint sizeOffset, jintArray type_ref, jint typeOffset) { + jint _exception = 0; + const char * _exceptionType; + const char * _exceptionMessage; + + GLint *size_base = (GLint *) 0; + jint _sizeRemaining; + GLint *size = (GLint *) 0; + + GLenum *type_base = (GLenum *) 0; + jint _typeRemaining; + GLenum *type = (GLenum *) 0; + + jstring result = 0; + + GLint len = 0; + glGetProgramiv((GLuint)program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &len); + if (!len) { + return _env->NewStringUTF(""); + } + char* buf = (char*) malloc(len); + + if (buf == NULL) { + jniThrowException(_env, "java/lang/IllegalArgumentException", "out of memory"); + return NULL; + } + + if (!size_ref) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "size == null"; + goto exit; + } + if (sizeOffset < 0) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "sizeOffset < 0"; + goto exit; + } + _sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset; + size_base = (GLint *) + _env->GetPrimitiveArrayCritical(size_ref, (jboolean *)0); + size = size_base + sizeOffset; + + if (!type_ref) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "type == null"; + goto exit; + } + if (typeOffset < 0) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "typeOffset < 0"; + goto exit; + } + _typeRemaining = _env->GetArrayLength(type_ref) - typeOffset; + type_base = (GLenum *) + _env->GetPrimitiveArrayCritical(type_ref, (jboolean *)0); + type = type_base + typeOffset; + + glGetActiveUniform( + (GLuint)program, + (GLuint)index, + (GLsizei)len, + NULL, + (GLint *)size, + (GLenum *)type, + (char *)buf + ); + +exit: + if (type_base) { + _env->ReleasePrimitiveArrayCritical(type_ref, type_base, + _exception ? JNI_ABORT: 0); + } + if (size_base) { + _env->ReleasePrimitiveArrayCritical(size_ref, size_base, + _exception ? JNI_ABORT: 0); + } + if (_exception != 1) { + result = _env->NewStringUTF(buf); + } + if (buf) { + free(buf); + } + if (_exception) { + jniThrowException(_env, _exceptionType, _exceptionMessage); + } + if (result == 0) { + result = _env->NewStringUTF(""); + } + return result; +} + +/* void glGetActiveUniform ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) */ +static jstring +android_glGetActiveUniform2 + (JNIEnv *_env, jobject _this, jint program, jint index, jobject size_buf, jobject type_buf) { + jarray _sizeArray = (jarray) 0; + jint _sizeBufferOffset = (jint) 0; + jarray _typeArray = (jarray) 0; + jint _typeBufferOffset = (jint) 0; + jint _sizeRemaining; + GLint *size = (GLint *) 0; + jint _typeRemaining; + GLenum *type = (GLenum *) 0; + + jstring result = 0; + GLint len = 0; + glGetProgramiv((GLuint)program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &len); + if (!len) { + return _env->NewStringUTF(""); + } + char* buf = (char*) malloc(len); + + if (buf == NULL) { + jniThrowException(_env, "java/lang/IllegalArgumentException", "out of memory"); + return NULL; + } + + size = (GLint *)getPointer(_env, size_buf, &_sizeArray, &_sizeRemaining, &_sizeBufferOffset); + type = (GLenum *)getPointer(_env, type_buf, &_typeArray, &_typeRemaining, &_typeBufferOffset); + + if (size == NULL) { + char * _sizeBase = (char *)_env->GetPrimitiveArrayCritical(_sizeArray, (jboolean *) 0); + size = (GLint *) (_sizeBase + _sizeBufferOffset); + } + if (type == NULL) { + char * _typeBase = (char *)_env->GetPrimitiveArrayCritical(_typeArray, (jboolean *) 0); + type = (GLenum *) (_typeBase + _typeBufferOffset); + } + glGetActiveUniform( + (GLuint)program, + (GLuint)index, + len, + NULL, + (GLint *)size, + (GLenum *)type, + (char *)buf + ); + + if (_typeArray) { + releasePointer(_env, _typeArray, type, JNI_TRUE); + } + if (_sizeArray) { + releasePointer(_env, _sizeArray, size, JNI_TRUE); + } + result = _env->NewStringUTF(buf); + if (buf) { + free(buf); + } + return result; +} diff --git a/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.java b/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.java new file mode 100644 index 0000000..28aaa78 --- /dev/null +++ b/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.java @@ -0,0 +1,46 @@ + // C function void glGetActiveUniform ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) + + public static native void glGetActiveUniform( + int program, + int index, + int bufsize, + int[] length, + int lengthOffset, + int[] size, + int sizeOffset, + int[] type, + int typeOffset, + byte[] name, + int nameOffset + ); + + // C function void glGetActiveUniform ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) + + public static native void glGetActiveUniform( + int program, + int index, + int bufsize, + java.nio.IntBuffer length, + java.nio.IntBuffer size, + java.nio.IntBuffer type, + byte name + ); + // C function void glGetActiveUniform ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) + + public static native String glGetActiveUniform( + int program, + int index, + int[] size, + int sizeOffset, + int[] type, + int typeOffset + ); + + // C function void glGetActiveUniform ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) + + public static native String glGetActiveUniform( + int program, + int index, + java.nio.IntBuffer size, + java.nio.IntBuffer type + ); diff --git a/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.nativeReg b/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.nativeReg new file mode 100644 index 0000000..f0b5fd9 --- /dev/null +++ b/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.nativeReg @@ -0,0 +1,4 @@ +{"glGetActiveUniform", "(III[II[II[II[BI)V", (void *) android_glGetActiveUniform__III_3II_3II_3II_3BI }, +{"glGetActiveUniform", "(II[II[II)Ljava/lang/String;", (void *) android_glGetActiveUniform1 }, +{"glGetActiveUniform", "(IIILjava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;B)V", (void *) android_glGetActiveUniform__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2B }, +{"glGetActiveUniform", "(IILjava/nio/IntBuffer;Ljava/nio/IntBuffer;)Ljava/lang/String;", (void *) android_glGetActiveUniform2 }, diff --git a/opengl/tools/glgen/stubs/gles11/glGetShaderSource.cpp b/opengl/tools/glgen/stubs/gles11/glGetShaderSource.cpp new file mode 100644 index 0000000..a7e1cd2 --- /dev/null +++ b/opengl/tools/glgen/stubs/gles11/glGetShaderSource.cpp @@ -0,0 +1,111 @@ +/* void glGetShaderSource ( GLuint shader, GLsizei bufsize, GLsizei *length, char *source ) */ +static void +android_glGetShaderSource__II_3II_3BI + (JNIEnv *_env, jobject _this, jint shader, jint bufsize, jintArray length_ref, jint lengthOffset, jbyteArray source_ref, jint sourceOffset) { + jint _exception = 0; + const char * _exceptionType; + const char * _exceptionMessage; + GLsizei *length_base = (GLsizei *) 0; + jint _lengthRemaining; + GLsizei *length = (GLsizei *) 0; + char *source_base = (char *) 0; + jint _sourceRemaining; + char *source = (char *) 0; + + if (!length_ref) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "length == null"; + goto exit; + } + if (lengthOffset < 0) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "lengthOffset < 0"; + goto exit; + } + _lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset; + length_base = (GLsizei *) + _env->GetPrimitiveArrayCritical(length_ref, (jboolean *)0); + length = length_base + lengthOffset; + + if (!source_ref) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "source == null"; + goto exit; + } + if (sourceOffset < 0) { + _exception = 1; + _exceptionType = "java/lang/IllegalArgumentException"; + _exceptionMessage = "sourceOffset < 0"; + goto exit; + } + _sourceRemaining = _env->GetArrayLength(source_ref) - sourceOffset; + source_base = (char *) + _env->GetPrimitiveArrayCritical(source_ref, (jboolean *)0); + source = source_base + sourceOffset; + + glGetShaderSource( + (GLuint)shader, + (GLsizei)bufsize, + (GLsizei *)length, + (char *)source + ); + +exit: + if (source_base) { + _env->ReleasePrimitiveArrayCritical(source_ref, source_base, + _exception ? JNI_ABORT: 0); + } + if (length_base) { + _env->ReleasePrimitiveArrayCritical(length_ref, length_base, + _exception ? JNI_ABORT: 0); + } + if (_exception) { + jniThrowException(_env, _exceptionType, _exceptionMessage); + } +} + +/* void glGetShaderSource ( GLuint shader, GLsizei bufsize, GLsizei *length, char *source ) */ +static void +android_glGetShaderSource__IILjava_nio_IntBuffer_2B + (JNIEnv *_env, jobject _this, jint shader, jint bufsize, jobject length_buf, jbyte source) { + jarray _array = (jarray) 0; + jint _bufferOffset = (jint) 0; + jint _remaining; + GLsizei *length = (GLsizei *) 0; + + length = (GLsizei *)getPointer(_env, length_buf, &_array, &_remaining, &_bufferOffset); + if (length == NULL) { + char * _lengthBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0); + length = (GLsizei *) (_lengthBase + _bufferOffset); + } + glGetShaderSource( + (GLuint)shader, + (GLsizei)bufsize, + (GLsizei *)length, + (char *)source + ); + if (_array) { + releasePointer(_env, _array, length, JNI_TRUE); + } +} + +/* void glGetShaderSource ( GLuint shader, GLsizei bufsize, GLsizei *length, char *source ) */ +static jstring android_glGetShaderSource(JNIEnv *_env, jobject, jint shader) { + GLint shaderLen = 0; + glGetShaderiv((GLuint)shader, GL_SHADER_SOURCE_LENGTH, &shaderLen); + if (!shaderLen) { + return _env->NewStringUTF(""); + } + char* buf = (char*) malloc(shaderLen); + if (buf == NULL) { + jniThrowException(_env, "java/lang/IllegalArgumentException", "out of memory"); + return NULL; + } + glGetShaderSource(shader, shaderLen, NULL, buf); + jstring result = _env->NewStringUTF(buf); + free(buf); + return result; +} diff --git a/opengl/tools/glgen/stubs/gles11/glGetShaderSource.java b/opengl/tools/glgen/stubs/gles11/glGetShaderSource.java new file mode 100644 index 0000000..199d93a --- /dev/null +++ b/opengl/tools/glgen/stubs/gles11/glGetShaderSource.java @@ -0,0 +1,25 @@ + // C function void glGetShaderSource ( GLuint shader, GLsizei bufsize, GLsizei *length, char *source ) + + public static native void glGetShaderSource( + int shader, + int bufsize, + int[] length, + int lengthOffset, + byte[] source, + int sourceOffset + ); + + // C function void glGetShaderSource ( GLuint shader, GLsizei bufsize, GLsizei *length, char *source ) + + public static native void glGetShaderSource( + int shader, + int bufsize, + java.nio.IntBuffer length, + byte source + ); + + // C function void glGetShaderSource ( GLuint shader, GLsizei bufsize, GLsizei *length, char *source ) + + public static native String glGetShaderSource( + int shader + ); diff --git a/opengl/tools/glgen/stubs/gles11/glGetShaderSource.nativeReg b/opengl/tools/glgen/stubs/gles11/glGetShaderSource.nativeReg new file mode 100644 index 0000000..acb47a5 --- /dev/null +++ b/opengl/tools/glgen/stubs/gles11/glGetShaderSource.nativeReg @@ -0,0 +1,3 @@ +{"glGetShaderSource", "(II[II[BI)V", (void *) android_glGetShaderSource__II_3II_3BI }, +{"glGetShaderSource", "(IILjava/nio/IntBuffer;B)V", (void *) android_glGetShaderSource__IILjava_nio_IntBuffer_2B }, +{"glGetShaderSource", "(I)Ljava/lang/String;", (void *) android_glGetShaderSource }, diff --git a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp index f7315ee..cc10336 100644 --- a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp +++ b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp @@ -113,14 +113,12 @@ nativeClassInit(JNIEnv *_env, jclass glImplClass) } static void * -getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining) +getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *offset) { jint position; jint limit; jint elementSizeShift; jlong pointer; - jint offset; - void *data; position = _env->GetIntField(buffer, positionID); limit = _env->GetIntField(buffer, limitID); @@ -138,11 +136,10 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining) if (*array == NULL) { return (void*) NULL; } - offset = _env->CallStaticIntMethod(nioAccessClass, + *offset = _env->CallStaticIntMethod(nioAccessClass, getBaseArrayOffsetID, buffer); - data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0); - return (void *) ((char *) data + offset); + return NULL; } static void @@ -180,10 +177,12 @@ getDirectBufferPointer(JNIEnv *_env, jobject buffer) { if (allowIndirectBuffers(_env)) { jarray array = 0; jint remaining; - buf = getPointer(_env, buffer, &array, &remaining); + jint offset; + buf = getPointer(_env, buffer, &array, &remaining, &offset); if (array) { releasePointer(_env, array, buf, 0); } + buf = buf + offset; } else { jniThrowException(_env, "java/lang/IllegalArgumentException", "Must use a native order direct Buffer"); diff --git a/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl b/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl index cd730aa..e3aea76 100644 --- a/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl +++ b/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl @@ -22,6 +22,7 @@ import android.app.AppGlobals; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.os.Build; +import android.os.UserId; import android.util.Log; import java.nio.Buffer; @@ -66,7 +67,7 @@ public class GLImpl implements GL10, GL10Ext, GL11, GL11Ext, GL11ExtensionPack { int version = 0; IPackageManager pm = AppGlobals.getPackageManager(); try { - ApplicationInfo applicationInfo = pm.getApplicationInfo(appName, 0); + ApplicationInfo applicationInfo = pm.getApplicationInfo(appName, 0, UserId.myUserId()); if (applicationInfo != null) { version = applicationInfo.targetSdkVersion; } diff --git a/services/powermanager/IPowerManager.cpp b/services/powermanager/IPowerManager.cpp index a0f19d4..0265df3 100644 --- a/services/powermanager/IPowerManager.cpp +++ b/services/powermanager/IPowerManager.cpp @@ -30,7 +30,7 @@ namespace android { // must be kept in sync with IPowerManager.aidl enum { ACQUIRE_WAKE_LOCK = IBinder::FIRST_CALL_TRANSACTION, - RELEASE_WAKE_LOCK = IBinder::FIRST_CALL_TRANSACTION + 4, + RELEASE_WAKE_LOCK = IBinder::FIRST_CALL_TRANSACTION + 1, }; class BpPowerManager : public BpInterface<IPowerManager> @@ -46,11 +46,10 @@ public: Parcel data, reply; data.writeInterfaceToken(IPowerManager::getInterfaceDescriptor()); - data.writeInt32(flags); data.writeStrongBinder(lock); + data.writeInt32(flags); data.writeString16(tag); - // no WorkSource passed - data.writeInt32(0); + data.writeInt32(0); // no WorkSource return remote()->transact(ACQUIRE_WAKE_LOCK, data, &reply); } diff --git a/services/sensorservice/Android.mk b/services/sensorservice/Android.mk new file mode 100644 index 0000000..6a302c0 --- /dev/null +++ b/services/sensorservice/Android.mk @@ -0,0 +1,31 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + CorrectedGyroSensor.cpp \ + Fusion.cpp \ + GravitySensor.cpp \ + LinearAccelerationSensor.cpp \ + OrientationSensor.cpp \ + RotationVectorSensor.cpp \ + SensorDevice.cpp \ + SensorFusion.cpp \ + SensorInterface.cpp \ + SensorService.cpp \ + + +LOCAL_CFLAGS:= -DLOG_TAG=\"SensorService\" + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libhardware \ + libutils \ + libbinder \ + libui \ + libgui + + + +LOCAL_MODULE:= libsensorservice + +include $(BUILD_SHARED_LIBRARY) diff --git a/services/sensorservice/CorrectedGyroSensor.cpp b/services/sensorservice/CorrectedGyroSensor.cpp new file mode 100644 index 0000000..1857443 --- /dev/null +++ b/services/sensorservice/CorrectedGyroSensor.cpp @@ -0,0 +1,86 @@ +/* + * 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. + */ + +#include <stdint.h> +#include <math.h> +#include <sys/types.h> + +#include <utils/Errors.h> + +#include <hardware/sensors.h> + +#include "CorrectedGyroSensor.h" +#include "SensorDevice.h" +#include "SensorFusion.h" + +namespace android { +// --------------------------------------------------------------------------- + +CorrectedGyroSensor::CorrectedGyroSensor(sensor_t const* list, size_t count) + : mSensorDevice(SensorDevice::getInstance()), + mSensorFusion(SensorFusion::getInstance()) +{ + for (size_t i=0 ; i<count ; i++) { + if (list[i].type == SENSOR_TYPE_GYROSCOPE) { + mGyro = Sensor(list + i); + break; + } + } +} + +bool CorrectedGyroSensor::process(sensors_event_t* outEvent, + const sensors_event_t& event) +{ + if (event.type == SENSOR_TYPE_GYROSCOPE) { + const vec3_t bias(mSensorFusion.getGyroBias()); + *outEvent = event; + outEvent->data[0] -= bias.x; + outEvent->data[1] -= bias.y; + outEvent->data[2] -= bias.z; + outEvent->sensor = '_cgy'; + return true; + } + return false; +} + +status_t CorrectedGyroSensor::activate(void* ident, bool enabled) { + mSensorDevice.activate(this, mGyro.getHandle(), enabled); + return mSensorFusion.activate(this, enabled); +} + +status_t CorrectedGyroSensor::setDelay(void* ident, int handle, int64_t ns) { + mSensorDevice.setDelay(this, mGyro.getHandle(), ns); + return mSensorFusion.setDelay(this, ns); +} + +Sensor CorrectedGyroSensor::getSensor() const { + sensor_t hwSensor; + hwSensor.name = "Corrected Gyroscope Sensor"; + hwSensor.vendor = "Google Inc."; + hwSensor.version = 1; + hwSensor.handle = '_cgy'; + hwSensor.type = SENSOR_TYPE_GYROSCOPE; + hwSensor.maxRange = mGyro.getMaxValue(); + hwSensor.resolution = mGyro.getResolution(); + hwSensor.power = mSensorFusion.getPowerUsage(); + hwSensor.minDelay = mGyro.getMinDelay(); + Sensor sensor(&hwSensor); + return sensor; +} + +// --------------------------------------------------------------------------- +}; // namespace android + diff --git a/services/sensorservice/CorrectedGyroSensor.h b/services/sensorservice/CorrectedGyroSensor.h new file mode 100644 index 0000000..3c49c08 --- /dev/null +++ b/services/sensorservice/CorrectedGyroSensor.h @@ -0,0 +1,52 @@ +/* + * 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. + */ + +#ifndef ANDROID_CORRECTED_GYRO_SENSOR_H +#define ANDROID_CORRECTED_GYRO_SENSOR_H + +#include <stdint.h> +#include <sys/types.h> + +#include <gui/Sensor.h> + +#include "SensorInterface.h" + +// --------------------------------------------------------------------------- +namespace android { +// --------------------------------------------------------------------------- + +class SensorDevice; +class SensorFusion; + +class CorrectedGyroSensor : public SensorInterface { + SensorDevice& mSensorDevice; + SensorFusion& mSensorFusion; + Sensor mGyro; + +public: + CorrectedGyroSensor(sensor_t const* list, size_t count); + virtual bool process(sensors_event_t* outEvent, + const sensors_event_t& event); + virtual status_t activate(void* ident, bool enabled); + virtual status_t setDelay(void* ident, int handle, int64_t ns); + virtual Sensor getSensor() const; + virtual bool isVirtual() const { return true; } +}; + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_CORRECTED_GYRO_SENSOR_H diff --git a/services/sensorservice/Fusion.cpp b/services/sensorservice/Fusion.cpp new file mode 100644 index 0000000..93d6127 --- /dev/null +++ b/services/sensorservice/Fusion.cpp @@ -0,0 +1,497 @@ +/* + * 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. + */ + +#include <stdio.h> + +#include <utils/Log.h> + +#include "Fusion.h" + +namespace android { + +// ----------------------------------------------------------------------- + +/* + * gyroVAR gives the measured variance of the gyro's output per + * Hz (or variance at 1 Hz). This is an "intrinsic" parameter of the gyro, + * which is independent of the sampling frequency. + * + * The variance of gyro's output at a given sampling period can be + * calculated as: + * variance(T) = gyroVAR / T + * + * The variance of the INTEGRATED OUTPUT at a given sampling period can be + * calculated as: + * variance_integrate_output(T) = gyroVAR * T + * + */ +static const float gyroVAR = 1e-7; // (rad/s)^2 / Hz +static const float biasVAR = 1e-8; // (rad/s)^2 / s (guessed) + +/* + * Standard deviations of accelerometer and magnetometer + */ +static const float accSTDEV = 0.05f; // m/s^2 (measured 0.08 / CDD 0.05) +static const float magSTDEV = 0.5f; // uT (measured 0.7 / CDD 0.5) + +static const float SYMMETRY_TOLERANCE = 1e-10f; + +/* + * Accelerometer updates will not be performed near free fall to avoid + * ill-conditioning and div by zeros. + * Threshhold: 10% of g, in m/s^2 + */ +static const float FREE_FALL_THRESHOLD = 0.981f; +static const float FREE_FALL_THRESHOLD_SQ = + FREE_FALL_THRESHOLD*FREE_FALL_THRESHOLD; + +/* + * The geomagnetic-field should be between 30uT and 60uT. + * Fields strengths greater than this likely indicate a local magnetic + * disturbance which we do not want to update into the fused frame. + */ +static const float MAX_VALID_MAGNETIC_FIELD = 100; // uT +static const float MAX_VALID_MAGNETIC_FIELD_SQ = + MAX_VALID_MAGNETIC_FIELD*MAX_VALID_MAGNETIC_FIELD; + +/* + * Values of the field smaller than this should be ignored in fusion to avoid + * ill-conditioning. This state can happen with anomalous local magnetic + * disturbances canceling the Earth field. + */ +static const float MIN_VALID_MAGNETIC_FIELD = 10; // uT +static const float MIN_VALID_MAGNETIC_FIELD_SQ = + MIN_VALID_MAGNETIC_FIELD*MIN_VALID_MAGNETIC_FIELD; + +/* + * If the cross product of two vectors has magnitude squared less than this, + * we reject it as invalid due to alignment of the vectors. + * This threshold is used to check for the case where the magnetic field sample + * is parallel to the gravity field, which can happen in certain places due + * to magnetic field disturbances. + */ +static const float MIN_VALID_CROSS_PRODUCT_MAG = 1.0e-3; +static const float MIN_VALID_CROSS_PRODUCT_MAG_SQ = + MIN_VALID_CROSS_PRODUCT_MAG*MIN_VALID_CROSS_PRODUCT_MAG; + +// ----------------------------------------------------------------------- + +template <typename TYPE, size_t C, size_t R> +static mat<TYPE, R, R> scaleCovariance( + const mat<TYPE, C, R>& A, + const mat<TYPE, C, C>& P) { + // A*P*transpose(A); + mat<TYPE, R, R> APAt; + for (size_t r=0 ; r<R ; r++) { + for (size_t j=r ; j<R ; j++) { + double apat(0); + for (size_t c=0 ; c<C ; c++) { + double v(A[c][r]*P[c][c]*0.5); + for (size_t k=c+1 ; k<C ; k++) + v += A[k][r] * P[c][k]; + apat += 2 * v * A[c][j]; + } + APAt[j][r] = apat; + APAt[r][j] = apat; + } + } + return APAt; +} + +template <typename TYPE, typename OTHER_TYPE> +static mat<TYPE, 3, 3> crossMatrix(const vec<TYPE, 3>& p, OTHER_TYPE diag) { + mat<TYPE, 3, 3> r; + r[0][0] = diag; + r[1][1] = diag; + r[2][2] = diag; + r[0][1] = p.z; + r[1][0] =-p.z; + r[0][2] =-p.y; + r[2][0] = p.y; + r[1][2] = p.x; + r[2][1] =-p.x; + return r; +} + + +template<typename TYPE, size_t SIZE> +class Covariance { + mat<TYPE, SIZE, SIZE> mSumXX; + vec<TYPE, SIZE> mSumX; + size_t mN; +public: + Covariance() : mSumXX(0.0f), mSumX(0.0f), mN(0) { } + void update(const vec<TYPE, SIZE>& x) { + mSumXX += x*transpose(x); + mSumX += x; + mN++; + } + mat<TYPE, SIZE, SIZE> operator()() const { + const float N = 1.0f / mN; + return mSumXX*N - (mSumX*transpose(mSumX))*(N*N); + } + void reset() { + mN = 0; + mSumXX = 0; + mSumX = 0; + } + size_t getCount() const { + return mN; + } +}; + +// ----------------------------------------------------------------------- + +Fusion::Fusion() { + Phi[0][1] = 0; + Phi[1][1] = 1; + + Ba.x = 0; + Ba.y = 0; + Ba.z = 1; + + Bm.x = 0; + Bm.y = 1; + Bm.z = 0; + + x0 = 0; + x1 = 0; + + init(); +} + +void Fusion::init() { + mInitState = 0; + + mGyroRate = 0; + + mCount[0] = 0; + mCount[1] = 0; + mCount[2] = 0; + + mData = 0; +} + +void Fusion::initFusion(const vec4_t& q, float dT) +{ + // initial estimate: E{ x(t0) } + x0 = q; + x1 = 0; + + // process noise covariance matrix: G.Q.Gt, with + // + // G = | -1 0 | Q = | q00 q10 | + // | 0 1 | | q01 q11 | + // + // q00 = sv^2.dt + 1/3.su^2.dt^3 + // q10 = q01 = 1/2.su^2.dt^2 + // q11 = su^2.dt + // + + const float dT2 = dT*dT; + const float dT3 = dT2*dT; + + // variance of integrated output at 1/dT Hz (random drift) + const float q00 = gyroVAR * dT + 0.33333f * biasVAR * dT3; + + // variance of drift rate ramp + const float q11 = biasVAR * dT; + const float q10 = 0.5f * biasVAR * dT2; + const float q01 = q10; + + GQGt[0][0] = q00; // rad^2 + GQGt[1][0] = -q10; + GQGt[0][1] = -q01; + GQGt[1][1] = q11; // (rad/s)^2 + + // initial covariance: Var{ x(t0) } + // TODO: initialize P correctly + P = 0; + + // it is unclear how to set the initial covariance. It does affect + // how quickly the fusion converges. Experimentally it would take + // about 10 seconds at 200 Hz to estimate the gyro-drift with an + // initial covariance of 0, and about a second with an initial covariance + // of about 1 deg/s. + const float covv = 0; + const float covu = 0.5f * (float(M_PI) / 180); + mat33_t& Pv = P[0][0]; + Pv[0][0] = covv; + Pv[1][1] = covv; + Pv[2][2] = covv; + mat33_t& Pu = P[1][1]; + Pu[0][0] = covu; + Pu[1][1] = covu; + Pu[2][2] = covu; +} + +bool Fusion::hasEstimate() const { + return (mInitState == (MAG|ACC|GYRO)); +} + +bool Fusion::checkInitComplete(int what, const vec3_t& d, float dT) { + if (hasEstimate()) + return true; + + if (what == ACC) { + mData[0] += d * (1/length(d)); + mCount[0]++; + mInitState |= ACC; + } else if (what == MAG) { + mData[1] += d * (1/length(d)); + mCount[1]++; + mInitState |= MAG; + } else if (what == GYRO) { + mGyroRate = dT; + mData[2] += d*dT; + mCount[2]++; + if (mCount[2] == 64) { + // 64 samples is good enough to estimate the gyro drift and + // doesn't take too much time. + mInitState |= GYRO; + } + } + + if (mInitState == (MAG|ACC|GYRO)) { + // Average all the values we collected so far + mData[0] *= 1.0f/mCount[0]; + mData[1] *= 1.0f/mCount[1]; + mData[2] *= 1.0f/mCount[2]; + + // calculate the MRPs from the data collection, this gives us + // a rough estimate of our initial state + mat33_t R; + vec3_t up(mData[0]); + vec3_t east(cross_product(mData[1], up)); + east *= 1/length(east); + vec3_t north(cross_product(up, east)); + R << east << north << up; + const vec4_t q = matrixToQuat(R); + + initFusion(q, mGyroRate); + } + + return false; +} + +void Fusion::handleGyro(const vec3_t& w, float dT) { + if (!checkInitComplete(GYRO, w, dT)) + return; + + predict(w, dT); +} + +status_t Fusion::handleAcc(const vec3_t& a) { + // ignore acceleration data if we're close to free-fall + if (length_squared(a) < FREE_FALL_THRESHOLD_SQ) { + return BAD_VALUE; + } + + if (!checkInitComplete(ACC, a)) + return BAD_VALUE; + + const float l = 1/length(a); + update(a*l, Ba, accSTDEV*l); + return NO_ERROR; +} + +status_t Fusion::handleMag(const vec3_t& m) { + // the geomagnetic-field should be between 30uT and 60uT + // reject if too large to avoid spurious magnetic sources + const float magFieldSq = length_squared(m); + if (magFieldSq > MAX_VALID_MAGNETIC_FIELD_SQ) { + return BAD_VALUE; + } else if (magFieldSq < MIN_VALID_MAGNETIC_FIELD_SQ) { + // Also reject if too small since we will get ill-defined (zero mag) + // cross-products below + return BAD_VALUE; + } + + if (!checkInitComplete(MAG, m)) + return BAD_VALUE; + + // Orthogonalize the magnetic field to the gravity field, mapping it into + // tangent to Earth. + const vec3_t up( getRotationMatrix() * Ba ); + const vec3_t east( cross_product(m, up) ); + + // If the m and up vectors align, the cross product magnitude will + // approach 0. + // Reject this case as well to avoid div by zero problems and + // ill-conditioning below. + if (length_squared(east) < MIN_VALID_CROSS_PRODUCT_MAG_SQ) { + return BAD_VALUE; + } + + // If we have created an orthogonal magnetic field successfully, + // then pass it in as the update. + vec3_t north( cross_product(up, east) ); + + const float l = 1 / length(north); + north *= l; + + update(north, Bm, magSTDEV*l); + return NO_ERROR; +} + +void Fusion::checkState() { + // P needs to stay positive semidefinite or the fusion diverges. When we + // detect divergence, we reset the fusion. + // TODO(braun): Instead, find the reason for the divergence and fix it. + + if (!isPositiveSemidefinite(P[0][0], SYMMETRY_TOLERANCE) || + !isPositiveSemidefinite(P[1][1], SYMMETRY_TOLERANCE)) { + ALOGW("Sensor fusion diverged; resetting state."); + P = 0; + } +} + +vec4_t Fusion::getAttitude() const { + return x0; +} + +vec3_t Fusion::getBias() const { + return x1; +} + +mat33_t Fusion::getRotationMatrix() const { + return quatToMatrix(x0); +} + +mat34_t Fusion::getF(const vec4_t& q) { + mat34_t F; + + // This is used to compute the derivative of q + // F = | [q.xyz]x | + // | -q.xyz | + + F[0].x = q.w; F[1].x =-q.z; F[2].x = q.y; + F[0].y = q.z; F[1].y = q.w; F[2].y =-q.x; + F[0].z =-q.y; F[1].z = q.x; F[2].z = q.w; + F[0].w =-q.x; F[1].w =-q.y; F[2].w =-q.z; + return F; +} + +void Fusion::predict(const vec3_t& w, float dT) { + const vec4_t q = x0; + const vec3_t b = x1; + const vec3_t we = w - b; + + // q(k+1) = O(we)*q(k) + // -------------------- + // + // O(w) = | cos(0.5*||w||*dT)*I33 - [psi]x psi | + // | -psi' cos(0.5*||w||*dT) | + // + // psi = sin(0.5*||w||*dT)*w / ||w|| + // + // + // P(k+1) = Phi(k)*P(k)*Phi(k)' + G*Q(k)*G' + // ---------------------------------------- + // + // G = | -I33 0 | + // | 0 I33 | + // + // Phi = | Phi00 Phi10 | + // | 0 1 | + // + // Phi00 = I33 + // - [w]x * sin(||w||*dt)/||w|| + // + [w]x^2 * (1-cos(||w||*dT))/||w||^2 + // + // Phi10 = [w]x * (1 - cos(||w||*dt))/||w||^2 + // - [w]x^2 * (||w||*dT - sin(||w||*dt))/||w||^3 + // - I33*dT + + const mat33_t I33(1); + const mat33_t I33dT(dT); + const mat33_t wx(crossMatrix(we, 0)); + const mat33_t wx2(wx*wx); + const float lwedT = length(we)*dT; + const float hlwedT = 0.5f*lwedT; + const float ilwe = 1/length(we); + const float k0 = (1-cosf(lwedT))*(ilwe*ilwe); + const float k1 = sinf(lwedT); + const float k2 = cosf(hlwedT); + const vec3_t psi(sinf(hlwedT)*ilwe*we); + const mat33_t O33(crossMatrix(-psi, k2)); + mat44_t O; + O[0].xyz = O33[0]; O[0].w = -psi.x; + O[1].xyz = O33[1]; O[1].w = -psi.y; + O[2].xyz = O33[2]; O[2].w = -psi.z; + O[3].xyz = psi; O[3].w = k2; + + Phi[0][0] = I33 - wx*(k1*ilwe) + wx2*k0; + Phi[1][0] = wx*k0 - I33dT - wx2*(ilwe*ilwe*ilwe)*(lwedT-k1); + + x0 = O*q; + if (x0.w < 0) + x0 = -x0; + + P = Phi*P*transpose(Phi) + GQGt; + + checkState(); +} + +void Fusion::update(const vec3_t& z, const vec3_t& Bi, float sigma) { + vec4_t q(x0); + // measured vector in body space: h(p) = A(p)*Bi + const mat33_t A(quatToMatrix(q)); + const vec3_t Bb(A*Bi); + + // Sensitivity matrix H = dh(p)/dp + // H = [ L 0 ] + const mat33_t L(crossMatrix(Bb, 0)); + + // gain... + // K = P*Ht / [H*P*Ht + R] + vec<mat33_t, 2> K; + const mat33_t R(sigma*sigma); + const mat33_t S(scaleCovariance(L, P[0][0]) + R); + const mat33_t Si(invert(S)); + const mat33_t LtSi(transpose(L)*Si); + K[0] = P[0][0] * LtSi; + K[1] = transpose(P[1][0])*LtSi; + + // update... + // P = (I-K*H) * P + // P -= K*H*P + // | K0 | * | L 0 | * P = | K0*L 0 | * | P00 P10 | = | K0*L*P00 K0*L*P10 | + // | K1 | | K1*L 0 | | P01 P11 | | K1*L*P00 K1*L*P10 | + // Note: the Joseph form is numerically more stable and given by: + // P = (I-KH) * P * (I-KH)' + K*R*R' + const mat33_t K0L(K[0] * L); + const mat33_t K1L(K[1] * L); + P[0][0] -= K0L*P[0][0]; + P[1][1] -= K1L*P[1][0]; + P[1][0] -= K0L*P[1][0]; + P[0][1] = transpose(P[1][0]); + + const vec3_t e(z - Bb); + const vec3_t dq(K[0]*e); + const vec3_t db(K[1]*e); + + q += getF(q)*(0.5f*dq); + x0 = normalize_quat(q); + x1 += db; + + checkState(); +} + +// ----------------------------------------------------------------------- + +}; // namespace android + diff --git a/services/sensorservice/Fusion.h b/services/sensorservice/Fusion.h new file mode 100644 index 0000000..7062999 --- /dev/null +++ b/services/sensorservice/Fusion.h @@ -0,0 +1,85 @@ +/* + * 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. + */ + +#ifndef ANDROID_FUSION_H +#define ANDROID_FUSION_H + +#include <utils/Errors.h> + +#include "quat.h" +#include "mat.h" +#include "vec.h" + +namespace android { + +typedef mat<float, 3, 4> mat34_t; + +class Fusion { + /* + * the state vector is made of two sub-vector containing respectively: + * - modified Rodrigues parameters + * - the estimated gyro bias + */ + quat_t x0; + vec3_t x1; + + /* + * the predicated covariance matrix is made of 4 3x3 sub-matrices and it is + * semi-definite positive. + * + * P = | P00 P10 | = | P00 P10 | + * | P01 P11 | | P10t P11 | + * + * Since P01 = transpose(P10), the code below never calculates or + * stores P01. + */ + mat<mat33_t, 2, 2> P; + + /* + * the process noise covariance matrix + */ + mat<mat33_t, 2, 2> GQGt; + +public: + Fusion(); + void init(); + void handleGyro(const vec3_t& w, float dT); + status_t handleAcc(const vec3_t& a); + status_t handleMag(const vec3_t& m); + vec4_t getAttitude() const; + vec3_t getBias() const; + mat33_t getRotationMatrix() const; + bool hasEstimate() const; + +private: + mat<mat33_t, 2, 2> Phi; + vec3_t Ba, Bm; + uint32_t mInitState; + float mGyroRate; + vec<vec3_t, 3> mData; + size_t mCount[3]; + enum { ACC=0x1, MAG=0x2, GYRO=0x4 }; + bool checkInitComplete(int, const vec3_t& w, float d = 0); + void initFusion(const vec4_t& q0, float dT); + void checkState(); + void predict(const vec3_t& w, float dT); + void update(const vec3_t& z, const vec3_t& Bi, float sigma); + static mat34_t getF(const vec4_t& p); +}; + +}; // namespace android + +#endif // ANDROID_FUSION_H diff --git a/services/sensorservice/GravitySensor.cpp b/services/sensorservice/GravitySensor.cpp new file mode 100644 index 0000000..c57715f --- /dev/null +++ b/services/sensorservice/GravitySensor.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2010 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 <math.h> +#include <sys/types.h> + +#include <utils/Errors.h> + +#include <hardware/sensors.h> + +#include "GravitySensor.h" +#include "SensorDevice.h" +#include "SensorFusion.h" + +namespace android { +// --------------------------------------------------------------------------- + +GravitySensor::GravitySensor(sensor_t const* list, size_t count) + : mSensorDevice(SensorDevice::getInstance()), + mSensorFusion(SensorFusion::getInstance()) +{ + for (size_t i=0 ; i<count ; i++) { + if (list[i].type == SENSOR_TYPE_ACCELEROMETER) { + mAccelerometer = Sensor(list + i); + break; + } + } +} + +bool GravitySensor::process(sensors_event_t* outEvent, + const sensors_event_t& event) +{ + const static double NS2S = 1.0 / 1000000000.0; + if (event.type == SENSOR_TYPE_ACCELEROMETER) { + vec3_t g; + if (!mSensorFusion.hasEstimate()) + return false; + const mat33_t R(mSensorFusion.getRotationMatrix()); + // FIXME: we need to estimate the length of gravity because + // the accelerometer may have a small scaling error. This + // translates to an offset in the linear-acceleration sensor. + g = R[2] * GRAVITY_EARTH; + + *outEvent = event; + outEvent->data[0] = g.x; + outEvent->data[1] = g.y; + outEvent->data[2] = g.z; + outEvent->sensor = '_grv'; + outEvent->type = SENSOR_TYPE_GRAVITY; + return true; + } + return false; +} + +status_t GravitySensor::activate(void* ident, bool enabled) { + return mSensorFusion.activate(this, enabled); +} + +status_t GravitySensor::setDelay(void* ident, int handle, int64_t ns) { + return mSensorFusion.setDelay(this, ns); +} + +Sensor GravitySensor::getSensor() const { + sensor_t hwSensor; + hwSensor.name = "Gravity Sensor"; + hwSensor.vendor = "Google Inc."; + hwSensor.version = 3; + hwSensor.handle = '_grv'; + hwSensor.type = SENSOR_TYPE_GRAVITY; + hwSensor.maxRange = GRAVITY_EARTH * 2; + hwSensor.resolution = mAccelerometer.getResolution(); + hwSensor.power = mSensorFusion.getPowerUsage(); + hwSensor.minDelay = mSensorFusion.getMinDelay(); + Sensor sensor(&hwSensor); + return sensor; +} + +// --------------------------------------------------------------------------- +}; // namespace android + diff --git a/services/sensorservice/GravitySensor.h b/services/sensorservice/GravitySensor.h new file mode 100644 index 0000000..ac177c4 --- /dev/null +++ b/services/sensorservice/GravitySensor.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_GRAVITY_SENSOR_H +#define ANDROID_GRAVITY_SENSOR_H + +#include <stdint.h> +#include <sys/types.h> + +#include <gui/Sensor.h> + +#include "SensorInterface.h" + +// --------------------------------------------------------------------------- +namespace android { +// --------------------------------------------------------------------------- + +class SensorDevice; +class SensorFusion; + +class GravitySensor : public SensorInterface { + SensorDevice& mSensorDevice; + SensorFusion& mSensorFusion; + Sensor mAccelerometer; + +public: + GravitySensor(sensor_t const* list, size_t count); + virtual bool process(sensors_event_t* outEvent, + const sensors_event_t& event); + virtual status_t activate(void* ident, bool enabled); + virtual status_t setDelay(void* ident, int handle, int64_t ns); + virtual Sensor getSensor() const; + virtual bool isVirtual() const { return true; } +}; + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_GRAVITY_SENSOR_H diff --git a/services/sensorservice/LinearAccelerationSensor.cpp b/services/sensorservice/LinearAccelerationSensor.cpp new file mode 100644 index 0000000..f0054f2 --- /dev/null +++ b/services/sensorservice/LinearAccelerationSensor.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2010 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 <math.h> +#include <sys/types.h> + +#include <utils/Errors.h> + +#include <hardware/sensors.h> + +#include "LinearAccelerationSensor.h" +#include "SensorDevice.h" +#include "SensorFusion.h" + +namespace android { +// --------------------------------------------------------------------------- + +LinearAccelerationSensor::LinearAccelerationSensor(sensor_t const* list, size_t count) + : mSensorDevice(SensorDevice::getInstance()), + mGravitySensor(list, count) +{ +} + +bool LinearAccelerationSensor::process(sensors_event_t* outEvent, + const sensors_event_t& event) +{ + bool result = mGravitySensor.process(outEvent, event); + if (result && event.type == SENSOR_TYPE_ACCELEROMETER) { + outEvent->data[0] = event.acceleration.x - outEvent->data[0]; + outEvent->data[1] = event.acceleration.y - outEvent->data[1]; + outEvent->data[2] = event.acceleration.z - outEvent->data[2]; + outEvent->sensor = '_lin'; + outEvent->type = SENSOR_TYPE_LINEAR_ACCELERATION; + return true; + } + return false; +} + +status_t LinearAccelerationSensor::activate(void* ident, bool enabled) { + return mGravitySensor.activate(this, enabled); +} + +status_t LinearAccelerationSensor::setDelay(void* ident, int handle, int64_t ns) { + return mGravitySensor.setDelay(this, handle, ns); +} + +Sensor LinearAccelerationSensor::getSensor() const { + Sensor gsensor(mGravitySensor.getSensor()); + sensor_t hwSensor; + hwSensor.name = "Linear Acceleration Sensor"; + hwSensor.vendor = "Google Inc."; + hwSensor.version = gsensor.getVersion(); + hwSensor.handle = '_lin'; + hwSensor.type = SENSOR_TYPE_LINEAR_ACCELERATION; + hwSensor.maxRange = gsensor.getMaxValue(); + hwSensor.resolution = gsensor.getResolution(); + hwSensor.power = gsensor.getPowerUsage(); + hwSensor.minDelay = gsensor.getMinDelay(); + Sensor sensor(&hwSensor); + return sensor; +} + +// --------------------------------------------------------------------------- +}; // namespace android + diff --git a/services/sensorservice/LinearAccelerationSensor.h b/services/sensorservice/LinearAccelerationSensor.h new file mode 100644 index 0000000..5deb24f --- /dev/null +++ b/services/sensorservice/LinearAccelerationSensor.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_LINEAR_ACCELERATION_SENSOR_H +#define ANDROID_LINEAR_ACCELERATION_SENSOR_H + +#include <stdint.h> +#include <sys/types.h> + +#include <gui/Sensor.h> + +#include "SensorInterface.h" +#include "GravitySensor.h" + +// --------------------------------------------------------------------------- +namespace android { +// --------------------------------------------------------------------------- + +class SensorDevice; +class SensorFusion; + +class LinearAccelerationSensor : public SensorInterface { + SensorDevice& mSensorDevice; + GravitySensor mGravitySensor; + + virtual bool process(sensors_event_t* outEvent, + const sensors_event_t& event); +public: + LinearAccelerationSensor(sensor_t const* list, size_t count); + virtual status_t activate(void* ident, bool enabled); + virtual status_t setDelay(void* ident, int handle, int64_t ns); + virtual Sensor getSensor() const; + virtual bool isVirtual() const { return true; } +}; + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_LINEAR_ACCELERATION_SENSOR_H diff --git a/services/sensorservice/OrientationSensor.cpp b/services/sensorservice/OrientationSensor.cpp new file mode 100644 index 0000000..037adaa --- /dev/null +++ b/services/sensorservice/OrientationSensor.cpp @@ -0,0 +1,90 @@ +/* + * 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. + */ + +#include <stdint.h> +#include <math.h> +#include <sys/types.h> + +#include <utils/Errors.h> + +#include <hardware/sensors.h> + +#include "OrientationSensor.h" +#include "SensorDevice.h" +#include "SensorFusion.h" + +namespace android { +// --------------------------------------------------------------------------- + +OrientationSensor::OrientationSensor() + : mSensorDevice(SensorDevice::getInstance()), + mSensorFusion(SensorFusion::getInstance()) +{ +} + +bool OrientationSensor::process(sensors_event_t* outEvent, + const sensors_event_t& event) +{ + if (event.type == SENSOR_TYPE_ACCELEROMETER) { + if (mSensorFusion.hasEstimate()) { + vec3_t g; + const float rad2deg = 180 / M_PI; + const mat33_t R(mSensorFusion.getRotationMatrix()); + g[0] = atan2f(-R[1][0], R[0][0]) * rad2deg; + g[1] = atan2f(-R[2][1], R[2][2]) * rad2deg; + g[2] = asinf ( R[2][0]) * rad2deg; + if (g[0] < 0) + g[0] += 360; + + *outEvent = event; + outEvent->orientation.azimuth = g.x; + outEvent->orientation.pitch = g.y; + outEvent->orientation.roll = g.z; + outEvent->orientation.status = SENSOR_STATUS_ACCURACY_HIGH; + outEvent->sensor = '_ypr'; + outEvent->type = SENSOR_TYPE_ORIENTATION; + return true; + } + } + return false; +} + +status_t OrientationSensor::activate(void* ident, bool enabled) { + return mSensorFusion.activate(this, enabled); +} + +status_t OrientationSensor::setDelay(void* ident, int handle, int64_t ns) { + return mSensorFusion.setDelay(this, ns); +} + +Sensor OrientationSensor::getSensor() const { + sensor_t hwSensor; + hwSensor.name = "Orientation Sensor"; + hwSensor.vendor = "Google Inc."; + hwSensor.version = 1; + hwSensor.handle = '_ypr'; + hwSensor.type = SENSOR_TYPE_ORIENTATION; + hwSensor.maxRange = 360.0f; + hwSensor.resolution = 1.0f/256.0f; // FIXME: real value here + hwSensor.power = mSensorFusion.getPowerUsage(); + hwSensor.minDelay = mSensorFusion.getMinDelay(); + Sensor sensor(&hwSensor); + return sensor; +} + +// --------------------------------------------------------------------------- +}; // namespace android + diff --git a/include/private/gui/SharedBufferStack.h b/services/sensorservice/OrientationSensor.h index 0da03d1..855949d 100644 --- a/include/private/gui/SharedBufferStack.h +++ b/services/sensorservice/OrientationSensor.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 The Android Open Source Project + * 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. @@ -14,46 +14,38 @@ * limitations under the License. */ -#ifndef ANDROID_SF_SHARED_BUFFER_STACK_H -#define ANDROID_SF_SHARED_BUFFER_STACK_H +#ifndef ANDROID_ORIENTATION_SENSOR_H +#define ANDROID_ORIENTATION_SENSOR_H #include <stdint.h> #include <sys/types.h> -#include <utils/Debug.h> +#include <gui/Sensor.h> +#include "SensorInterface.h" + +// --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- -#define NUM_DISPLAY_MAX 4 - -struct display_cblk_t -{ - uint16_t w; - uint16_t h; - uint8_t format; - uint8_t orientation; - uint8_t reserved[2]; - float fps; - float density; - float xdpi; - float ydpi; - uint32_t pad[2]; -}; - -struct surface_flinger_cblk_t // 4KB max -{ - uint8_t connected; - uint8_t reserved[3]; - uint32_t pad[7]; - display_cblk_t displays[NUM_DISPLAY_MAX]; +class SensorDevice; +class SensorFusion; + +class OrientationSensor : public SensorInterface { + SensorDevice& mSensorDevice; + SensorFusion& mSensorFusion; + +public: + OrientationSensor(); + virtual bool process(sensors_event_t* outEvent, + const sensors_event_t& event); + virtual status_t activate(void* ident, bool enabled); + virtual status_t setDelay(void* ident, int handle, int64_t ns); + virtual Sensor getSensor() const; + virtual bool isVirtual() const { return true; } }; // --------------------------------------------------------------------------- - -COMPILE_TIME_ASSERT(sizeof(surface_flinger_cblk_t) <= 4096) - -// --------------------------------------------------------------------------- }; // namespace android -#endif /* ANDROID_SF_SHARED_BUFFER_STACK_H */ +#endif // ANDROID_ORIENTATION_SENSOR_H diff --git a/services/sensorservice/RotationVectorSensor.cpp b/services/sensorservice/RotationVectorSensor.cpp new file mode 100644 index 0000000..5ea9568 --- /dev/null +++ b/services/sensorservice/RotationVectorSensor.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2010 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 <math.h> +#include <sys/types.h> + +#include <utils/Errors.h> + +#include <hardware/sensors.h> + +#include "RotationVectorSensor.h" + +namespace android { +// --------------------------------------------------------------------------- + +RotationVectorSensor::RotationVectorSensor() + : mSensorDevice(SensorDevice::getInstance()), + mSensorFusion(SensorFusion::getInstance()) +{ +} + +bool RotationVectorSensor::process(sensors_event_t* outEvent, + const sensors_event_t& event) +{ + if (event.type == SENSOR_TYPE_ACCELEROMETER) { + if (mSensorFusion.hasEstimate()) { + const vec4_t q(mSensorFusion.getAttitude()); + *outEvent = event; + outEvent->data[0] = q.x; + outEvent->data[1] = q.y; + outEvent->data[2] = q.z; + outEvent->data[3] = q.w; + outEvent->sensor = '_rov'; + outEvent->type = SENSOR_TYPE_ROTATION_VECTOR; + return true; + } + } + return false; +} + +status_t RotationVectorSensor::activate(void* ident, bool enabled) { + return mSensorFusion.activate(this, enabled); +} + +status_t RotationVectorSensor::setDelay(void* ident, int handle, int64_t ns) { + return mSensorFusion.setDelay(this, ns); +} + +Sensor RotationVectorSensor::getSensor() const { + sensor_t hwSensor; + hwSensor.name = "Rotation Vector Sensor"; + hwSensor.vendor = "Google Inc."; + hwSensor.version = 3; + hwSensor.handle = '_rov'; + hwSensor.type = SENSOR_TYPE_ROTATION_VECTOR; + hwSensor.maxRange = 1; + hwSensor.resolution = 1.0f / (1<<24); + hwSensor.power = mSensorFusion.getPowerUsage(); + hwSensor.minDelay = mSensorFusion.getMinDelay(); + Sensor sensor(&hwSensor); + return sensor; +} + +// --------------------------------------------------------------------------- + +GyroDriftSensor::GyroDriftSensor() + : mSensorDevice(SensorDevice::getInstance()), + mSensorFusion(SensorFusion::getInstance()) +{ +} + +bool GyroDriftSensor::process(sensors_event_t* outEvent, + const sensors_event_t& event) +{ + if (event.type == SENSOR_TYPE_ACCELEROMETER) { + if (mSensorFusion.hasEstimate()) { + const vec3_t b(mSensorFusion.getGyroBias()); + *outEvent = event; + outEvent->data[0] = b.x; + outEvent->data[1] = b.y; + outEvent->data[2] = b.z; + outEvent->sensor = '_gbs'; + outEvent->type = SENSOR_TYPE_ACCELEROMETER; + return true; + } + } + return false; +} + +status_t GyroDriftSensor::activate(void* ident, bool enabled) { + return mSensorFusion.activate(this, enabled); +} + +status_t GyroDriftSensor::setDelay(void* ident, int handle, int64_t ns) { + return mSensorFusion.setDelay(this, ns); +} + +Sensor GyroDriftSensor::getSensor() const { + sensor_t hwSensor; + hwSensor.name = "Gyroscope Bias (debug)"; + hwSensor.vendor = "Google Inc."; + hwSensor.version = 1; + hwSensor.handle = '_gbs'; + hwSensor.type = SENSOR_TYPE_ACCELEROMETER; + hwSensor.maxRange = 1; + hwSensor.resolution = 1.0f / (1<<24); + hwSensor.power = mSensorFusion.getPowerUsage(); + hwSensor.minDelay = mSensorFusion.getMinDelay(); + Sensor sensor(&hwSensor); + return sensor; +} + +// --------------------------------------------------------------------------- +}; // namespace android + diff --git a/services/sensorservice/RotationVectorSensor.h b/services/sensorservice/RotationVectorSensor.h new file mode 100644 index 0000000..bb97fe1 --- /dev/null +++ b/services/sensorservice/RotationVectorSensor.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_ROTATION_VECTOR_SENSOR_H +#define ANDROID_ROTATION_VECTOR_SENSOR_H + +#include <stdint.h> +#include <sys/types.h> + +#include <gui/Sensor.h> + +#include "SensorDevice.h" +#include "SensorInterface.h" + +#include "Fusion.h" +#include "SensorFusion.h" + +// --------------------------------------------------------------------------- +namespace android { +// --------------------------------------------------------------------------- + +class RotationVectorSensor : public SensorInterface { + SensorDevice& mSensorDevice; + SensorFusion& mSensorFusion; + +public: + RotationVectorSensor(); + virtual bool process(sensors_event_t* outEvent, + const sensors_event_t& event); + virtual status_t activate(void* ident, bool enabled); + virtual status_t setDelay(void* ident, int handle, int64_t ns); + virtual Sensor getSensor() const; + virtual bool isVirtual() const { return true; } +}; + +class GyroDriftSensor : public SensorInterface { + SensorDevice& mSensorDevice; + SensorFusion& mSensorFusion; + +public: + GyroDriftSensor(); + virtual bool process(sensors_event_t* outEvent, + const sensors_event_t& event); + virtual status_t activate(void* ident, bool enabled); + virtual status_t setDelay(void* ident, int handle, int64_t ns); + virtual Sensor getSensor() const; + virtual bool isVirtual() const { return true; } +}; + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_ROTATION_VECTOR_SENSOR_H diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp new file mode 100644 index 0000000..2244a86 --- /dev/null +++ b/services/sensorservice/SensorDevice.cpp @@ -0,0 +1,282 @@ +/* + * Copyright (C) 2010 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 <math.h> +#include <sys/types.h> + +#include <utils/Atomic.h> +#include <utils/Errors.h> +#include <utils/Singleton.h> + +#include <binder/BinderService.h> +#include <binder/Parcel.h> +#include <binder/IServiceManager.h> + +#include <hardware/sensors.h> + +#include "SensorDevice.h" +#include "SensorService.h" + +namespace android { +// --------------------------------------------------------------------------- +class BatteryService : public Singleton<BatteryService> { + static const int TRANSACTION_noteStartSensor = IBinder::FIRST_CALL_TRANSACTION + 3; + static const int TRANSACTION_noteStopSensor = IBinder::FIRST_CALL_TRANSACTION + 4; + static const String16 DESCRIPTOR; + + friend class Singleton<BatteryService>; + sp<IBinder> mBatteryStatService; + + BatteryService() { + const sp<IServiceManager> sm(defaultServiceManager()); + if (sm != NULL) { + const String16 name("batteryinfo"); + mBatteryStatService = sm->getService(name); + } + } + + status_t noteStartSensor(int uid, int handle) { + Parcel data, reply; + data.writeInterfaceToken(DESCRIPTOR); + data.writeInt32(uid); + data.writeInt32(handle); + status_t err = mBatteryStatService->transact( + TRANSACTION_noteStartSensor, data, &reply, 0); + err = reply.readExceptionCode(); + return err; + } + + status_t noteStopSensor(int uid, int handle) { + Parcel data, reply; + data.writeInterfaceToken(DESCRIPTOR); + data.writeInt32(uid); + data.writeInt32(handle); + status_t err = mBatteryStatService->transact( + TRANSACTION_noteStopSensor, data, &reply, 0); + err = reply.readExceptionCode(); + return err; + } + +public: + void enableSensor(int handle) { + if (mBatteryStatService != 0) { + int uid = IPCThreadState::self()->getCallingUid(); + int64_t identity = IPCThreadState::self()->clearCallingIdentity(); + noteStartSensor(uid, handle); + IPCThreadState::self()->restoreCallingIdentity(identity); + } + } + void disableSensor(int handle) { + if (mBatteryStatService != 0) { + int uid = IPCThreadState::self()->getCallingUid(); + int64_t identity = IPCThreadState::self()->clearCallingIdentity(); + noteStopSensor(uid, handle); + IPCThreadState::self()->restoreCallingIdentity(identity); + } + } +}; + +const String16 BatteryService::DESCRIPTOR("com.android.internal.app.IBatteryStats"); + +ANDROID_SINGLETON_STATIC_INSTANCE(BatteryService) + +// --------------------------------------------------------------------------- + +ANDROID_SINGLETON_STATIC_INSTANCE(SensorDevice) + +SensorDevice::SensorDevice() + : mSensorDevice(0), + mSensorModule(0) +{ + status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID, + (hw_module_t const**)&mSensorModule); + + ALOGE_IF(err, "couldn't load %s module (%s)", + SENSORS_HARDWARE_MODULE_ID, strerror(-err)); + + if (mSensorModule) { + err = sensors_open(&mSensorModule->common, &mSensorDevice); + + ALOGE_IF(err, "couldn't open device for module %s (%s)", + SENSORS_HARDWARE_MODULE_ID, strerror(-err)); + + if (mSensorDevice) { + sensor_t const* list; + ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list); + mActivationCount.setCapacity(count); + Info model; + for (size_t i=0 ; i<size_t(count) ; i++) { + mActivationCount.add(list[i].handle, model); + mSensorDevice->activate(mSensorDevice, list[i].handle, 0); + } + } + } +} + +void SensorDevice::dump(String8& result, char* buffer, size_t SIZE) +{ + if (!mSensorModule) return; + sensor_t const* list; + ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list); + + snprintf(buffer, SIZE, "%d h/w sensors:\n", int(count)); + result.append(buffer); + + Mutex::Autolock _l(mLock); + for (size_t i=0 ; i<size_t(count) ; i++) { + const Info& info = mActivationCount.valueFor(list[i].handle); + snprintf(buffer, SIZE, "handle=0x%08x, active-count=%d, rates(ms)={ ", + list[i].handle, + info.rates.size()); + result.append(buffer); + for (size_t j=0 ; j<info.rates.size() ; j++) { + snprintf(buffer, SIZE, "%4.1f%s", + info.rates.valueAt(j) / 1e6f, + j<info.rates.size()-1 ? ", " : ""); + result.append(buffer); + } + snprintf(buffer, SIZE, " }, selected=%4.1f ms\n", info.delay / 1e6f); + result.append(buffer); + } +} + +ssize_t SensorDevice::getSensorList(sensor_t const** list) { + if (!mSensorModule) return NO_INIT; + ssize_t count = mSensorModule->get_sensors_list(mSensorModule, list); + return count; +} + +status_t SensorDevice::initCheck() const { + return mSensorDevice && mSensorModule ? NO_ERROR : NO_INIT; +} + +ssize_t SensorDevice::poll(sensors_event_t* buffer, size_t count) { + if (!mSensorDevice) return NO_INIT; + ssize_t c; + do { + c = mSensorDevice->poll(mSensorDevice, buffer, count); + } while (c == -EINTR); + return c; +} + +status_t SensorDevice::activate(void* ident, int handle, int enabled) +{ + if (!mSensorDevice) return NO_INIT; + status_t err(NO_ERROR); + bool actuateHardware = false; + + Info& info( mActivationCount.editValueFor(handle) ); + + + ALOGD_IF(DEBUG_CONNECTIONS, + "SensorDevice::activate: ident=%p, handle=0x%08x, enabled=%d, count=%d", + ident, handle, enabled, info.rates.size()); + + if (enabled) { + Mutex::Autolock _l(mLock); + ALOGD_IF(DEBUG_CONNECTIONS, "... index=%ld", + info.rates.indexOfKey(ident)); + + if (info.rates.indexOfKey(ident) < 0) { + info.rates.add(ident, DEFAULT_EVENTS_PERIOD); + if (info.rates.size() == 1) { + actuateHardware = true; + } + } else { + // sensor was already activated for this ident + } + } else { + Mutex::Autolock _l(mLock); + ALOGD_IF(DEBUG_CONNECTIONS, "... index=%ld", + info.rates.indexOfKey(ident)); + + ssize_t idx = info.rates.removeItem(ident); + if (idx >= 0) { + if (info.rates.size() == 0) { + actuateHardware = true; + } + } else { + // sensor wasn't enabled for this ident + } + } + + if (actuateHardware) { + ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w"); + + err = mSensorDevice->activate(mSensorDevice, handle, enabled); + if (enabled) { + ALOGE_IF(err, "Error activating sensor %d (%s)", handle, strerror(-err)); + if (err == 0) { + BatteryService::getInstance().enableSensor(handle); + } + } else { + if (err == 0) { + BatteryService::getInstance().disableSensor(handle); + } + } + } + + { // scope for the lock + Mutex::Autolock _l(mLock); + nsecs_t ns = info.selectDelay(); + mSensorDevice->setDelay(mSensorDevice, handle, ns); + } + + return err; +} + +status_t SensorDevice::setDelay(void* ident, int handle, int64_t ns) +{ + if (!mSensorDevice) return NO_INIT; + Mutex::Autolock _l(mLock); + Info& info( mActivationCount.editValueFor(handle) ); + status_t err = info.setDelayForIdent(ident, ns); + if (err < 0) return err; + ns = info.selectDelay(); + return mSensorDevice->setDelay(mSensorDevice, handle, ns); +} + +// --------------------------------------------------------------------------- + +status_t SensorDevice::Info::setDelayForIdent(void* ident, int64_t ns) +{ + ssize_t index = rates.indexOfKey(ident); + if (index < 0) { + ALOGE("Info::setDelayForIdent(ident=%p, ns=%lld) failed (%s)", + ident, ns, strerror(-index)); + return BAD_INDEX; + } + rates.editValueAt(index) = ns; + return NO_ERROR; +} + +nsecs_t SensorDevice::Info::selectDelay() +{ + nsecs_t ns = rates.valueAt(0); + for (size_t i=1 ; i<rates.size() ; i++) { + nsecs_t cur = rates.valueAt(i); + if (cur < ns) { + ns = cur; + } + } + delay = ns; + return ns; +} + +// --------------------------------------------------------------------------- +}; // namespace android + diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h new file mode 100644 index 0000000..728b6cb --- /dev/null +++ b/services/sensorservice/SensorDevice.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_SENSOR_DEVICE_H +#define ANDROID_SENSOR_DEVICE_H + +#include <stdint.h> +#include <sys/types.h> + +#include <utils/KeyedVector.h> +#include <utils/Singleton.h> +#include <utils/String8.h> + +#include <gui/Sensor.h> + +// --------------------------------------------------------------------------- + +namespace android { +// --------------------------------------------------------------------------- + +static const nsecs_t DEFAULT_EVENTS_PERIOD = 200000000; // 5 Hz + +class SensorDevice : public Singleton<SensorDevice> { + friend class Singleton<SensorDevice>; + struct sensors_poll_device_t* mSensorDevice; + struct sensors_module_t* mSensorModule; + mutable Mutex mLock; // protect mActivationCount[].rates + // fixed-size array after construction + struct Info { + Info() : delay(0) { } + KeyedVector<void*, nsecs_t> rates; + nsecs_t delay; + status_t setDelayForIdent(void* ident, int64_t ns); + nsecs_t selectDelay(); + }; + DefaultKeyedVector<int, Info> mActivationCount; + + SensorDevice(); +public: + ssize_t getSensorList(sensor_t const** list); + status_t initCheck() const; + ssize_t poll(sensors_event_t* buffer, size_t count); + status_t activate(void* ident, int handle, int enabled); + status_t setDelay(void* ident, int handle, int64_t ns); + void dump(String8& result, char* buffer, size_t SIZE); +}; + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_SENSOR_DEVICE_H diff --git a/services/sensorservice/SensorFusion.cpp b/services/sensorservice/SensorFusion.cpp new file mode 100644 index 0000000..d23906d --- /dev/null +++ b/services/sensorservice/SensorFusion.cpp @@ -0,0 +1,148 @@ +/* + * 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. + */ + +#include "SensorDevice.h" +#include "SensorFusion.h" +#include "SensorService.h" + +namespace android { +// --------------------------------------------------------------------------- + +ANDROID_SINGLETON_STATIC_INSTANCE(SensorFusion) + +SensorFusion::SensorFusion() + : mSensorDevice(SensorDevice::getInstance()), + mEnabled(false), mGyroTime(0) +{ + sensor_t const* list; + ssize_t count = mSensorDevice.getSensorList(&list); + if (count > 0) { + for (size_t i=0 ; i<size_t(count) ; i++) { + if (list[i].type == SENSOR_TYPE_ACCELEROMETER) { + mAcc = Sensor(list + i); + } + if (list[i].type == SENSOR_TYPE_MAGNETIC_FIELD) { + mMag = Sensor(list + i); + } + if (list[i].type == SENSOR_TYPE_GYROSCOPE) { + mGyro = Sensor(list + i); + // 200 Hz for gyro events is a good compromise between precision + // and power/cpu usage. + mGyroRate = 200; + mTargetDelayNs = 1000000000LL/mGyroRate; + } + } + mFusion.init(); + } +} + +void SensorFusion::process(const sensors_event_t& event) { + if (event.type == SENSOR_TYPE_GYROSCOPE) { + if (mGyroTime != 0) { + const float dT = (event.timestamp - mGyroTime) / 1000000000.0f; + const float freq = 1 / dT; + if (freq >= 100 && freq<1000) { // filter values obviously wrong + const float alpha = 1 / (1 + dT); // 1s time-constant + mGyroRate = freq + (mGyroRate - freq)*alpha; + } + } + mGyroTime = event.timestamp; + mFusion.handleGyro(vec3_t(event.data), 1.0f/mGyroRate); + } else if (event.type == SENSOR_TYPE_MAGNETIC_FIELD) { + const vec3_t mag(event.data); + mFusion.handleMag(mag); + } else if (event.type == SENSOR_TYPE_ACCELEROMETER) { + const vec3_t acc(event.data); + mFusion.handleAcc(acc); + mAttitude = mFusion.getAttitude(); + } +} + +template <typename T> inline T min(T a, T b) { return a<b ? a : b; } +template <typename T> inline T max(T a, T b) { return a>b ? a : b; } + +status_t SensorFusion::activate(void* ident, bool enabled) { + + ALOGD_IF(DEBUG_CONNECTIONS, + "SensorFusion::activate(ident=%p, enabled=%d)", + ident, enabled); + + const ssize_t idx = mClients.indexOf(ident); + if (enabled) { + if (idx < 0) { + mClients.add(ident); + } + } else { + if (idx >= 0) { + mClients.removeItemsAt(idx); + } + } + + mSensorDevice.activate(ident, mAcc.getHandle(), enabled); + mSensorDevice.activate(ident, mMag.getHandle(), enabled); + mSensorDevice.activate(ident, mGyro.getHandle(), enabled); + + const bool newState = mClients.size() != 0; + if (newState != mEnabled) { + mEnabled = newState; + if (newState) { + mFusion.init(); + mGyroTime = 0; + } + } + return NO_ERROR; +} + +status_t SensorFusion::setDelay(void* ident, int64_t ns) { + mSensorDevice.setDelay(ident, mAcc.getHandle(), ns); + mSensorDevice.setDelay(ident, mMag.getHandle(), ms2ns(20)); + mSensorDevice.setDelay(ident, mGyro.getHandle(), mTargetDelayNs); + return NO_ERROR; +} + + +float SensorFusion::getPowerUsage() const { + float power = mAcc.getPowerUsage() + + mMag.getPowerUsage() + + mGyro.getPowerUsage(); + return power; +} + +int32_t SensorFusion::getMinDelay() const { + return mAcc.getMinDelay(); +} + +void SensorFusion::dump(String8& result, char* buffer, size_t SIZE) { + const Fusion& fusion(mFusion); + snprintf(buffer, SIZE, "9-axis fusion %s (%d clients), gyro-rate=%7.2fHz, " + "q=< %g, %g, %g, %g > (%g), " + "b=< %g, %g, %g >\n", + mEnabled ? "enabled" : "disabled", + mClients.size(), + mGyroRate, + fusion.getAttitude().x, + fusion.getAttitude().y, + fusion.getAttitude().z, + fusion.getAttitude().w, + length(fusion.getAttitude()), + fusion.getBias().x, + fusion.getBias().y, + fusion.getBias().z); + result.append(buffer); +} + +// --------------------------------------------------------------------------- +}; // namespace android diff --git a/services/sensorservice/SensorFusion.h b/services/sensorservice/SensorFusion.h new file mode 100644 index 0000000..4c99bcb --- /dev/null +++ b/services/sensorservice/SensorFusion.h @@ -0,0 +1,78 @@ +/* + * 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. + */ + +#ifndef ANDROID_SENSOR_FUSION_H +#define ANDROID_SENSOR_FUSION_H + +#include <stdint.h> +#include <sys/types.h> + +#include <utils/SortedVector.h> +#include <utils/Singleton.h> +#include <utils/String8.h> + +#include <gui/Sensor.h> + +#include "Fusion.h" + +// --------------------------------------------------------------------------- + +namespace android { +// --------------------------------------------------------------------------- + +class SensorDevice; + +class SensorFusion : public Singleton<SensorFusion> { + friend class Singleton<SensorFusion>; + + SensorDevice& mSensorDevice; + Sensor mAcc; + Sensor mMag; + Sensor mGyro; + Fusion mFusion; + bool mEnabled; + float mGyroRate; + nsecs_t mTargetDelayNs; + nsecs_t mGyroTime; + vec4_t mAttitude; + SortedVector<void*> mClients; + + SensorFusion(); + +public: + void process(const sensors_event_t& event); + + bool isEnabled() const { return mEnabled; } + bool hasEstimate() const { return mFusion.hasEstimate(); } + mat33_t getRotationMatrix() const { return mFusion.getRotationMatrix(); } + vec4_t getAttitude() const { return mAttitude; } + vec3_t getGyroBias() const { return mFusion.getBias(); } + float getEstimatedRate() const { return mGyroRate; } + + status_t activate(void* ident, bool enabled); + status_t setDelay(void* ident, int64_t ns); + + float getPowerUsage() const; + int32_t getMinDelay() const; + + void dump(String8& result, char* buffer, size_t SIZE); +}; + + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_SENSOR_FUSION_H diff --git a/services/sensorservice/SensorInterface.cpp b/services/sensorservice/SensorInterface.cpp new file mode 100644 index 0000000..468aa61 --- /dev/null +++ b/services/sensorservice/SensorInterface.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdint.h> +#include <sys/types.h> + +#include <cutils/log.h> + +#include "SensorInterface.h" + +namespace android { +// --------------------------------------------------------------------------- + +SensorInterface::~SensorInterface() +{ +} + +// --------------------------------------------------------------------------- + +HardwareSensor::HardwareSensor(const sensor_t& sensor) + : mSensorDevice(SensorDevice::getInstance()), + mSensor(&sensor) +{ + ALOGI("%s", sensor.name); +} + +HardwareSensor::~HardwareSensor() { +} + +bool HardwareSensor::process(sensors_event_t* outEvent, + const sensors_event_t& event) { + *outEvent = event; + return true; +} + +status_t HardwareSensor::activate(void* ident, bool enabled) { + return mSensorDevice.activate(ident, mSensor.getHandle(), enabled); +} + +status_t HardwareSensor::setDelay(void* ident, int handle, int64_t ns) { + return mSensorDevice.setDelay(ident, handle, ns); +} + +Sensor HardwareSensor::getSensor() const { + return mSensor; +} + + +// --------------------------------------------------------------------------- +}; // namespace android diff --git a/services/sensorservice/SensorInterface.h b/services/sensorservice/SensorInterface.h new file mode 100644 index 0000000..fb357d7 --- /dev/null +++ b/services/sensorservice/SensorInterface.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_SENSOR_INTERFACE_H +#define ANDROID_SENSOR_INTERFACE_H + +#include <stdint.h> +#include <sys/types.h> + +#include <gui/Sensor.h> + +#include "SensorDevice.h" + +// --------------------------------------------------------------------------- + +namespace android { +// --------------------------------------------------------------------------- + +class SensorInterface { +public: + virtual ~SensorInterface(); + + virtual bool process(sensors_event_t* outEvent, + const sensors_event_t& event) = 0; + + virtual status_t activate(void* ident, bool enabled) = 0; + virtual status_t setDelay(void* ident, int handle, int64_t ns) = 0; + virtual Sensor getSensor() const = 0; + virtual bool isVirtual() const = 0; +}; + +// --------------------------------------------------------------------------- + +class HardwareSensor : public SensorInterface +{ + SensorDevice& mSensorDevice; + Sensor mSensor; + +public: + HardwareSensor(const sensor_t& sensor); + + virtual ~HardwareSensor(); + + virtual bool process(sensors_event_t* outEvent, + const sensors_event_t& event); + + virtual status_t activate(void* ident, bool enabled); + virtual status_t setDelay(void* ident, int handle, int64_t ns); + virtual Sensor getSensor() const; + virtual bool isVirtual() const { return false; } +}; + + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_SENSOR_INTERFACE_H diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp new file mode 100644 index 0000000..7ab34c9 --- /dev/null +++ b/services/sensorservice/SensorService.cpp @@ -0,0 +1,657 @@ +/* + * Copyright (C) 2010 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 <math.h> +#include <sys/types.h> + +#include <cutils/properties.h> + +#include <utils/SortedVector.h> +#include <utils/KeyedVector.h> +#include <utils/threads.h> +#include <utils/Atomic.h> +#include <utils/Errors.h> +#include <utils/RefBase.h> +#include <utils/Singleton.h> +#include <utils/String16.h> + +#include <binder/BinderService.h> +#include <binder/IServiceManager.h> +#include <binder/PermissionCache.h> + +#include <gui/ISensorServer.h> +#include <gui/ISensorEventConnection.h> +#include <gui/SensorEventQueue.h> + +#include <hardware/sensors.h> + +#include "CorrectedGyroSensor.h" +#include "GravitySensor.h" +#include "LinearAccelerationSensor.h" +#include "OrientationSensor.h" +#include "RotationVectorSensor.h" +#include "SensorFusion.h" +#include "SensorService.h" + +namespace android { +// --------------------------------------------------------------------------- + +/* + * Notes: + * + * - what about a gyro-corrected magnetic-field sensor? + * - run mag sensor from time to time to force calibration + * - gravity sensor length is wrong (=> drift in linear-acc sensor) + * + */ + +SensorService::SensorService() + : mInitCheck(NO_INIT) +{ +} + +void SensorService::onFirstRef() +{ + ALOGD("nuSensorService starting..."); + + SensorDevice& dev(SensorDevice::getInstance()); + + if (dev.initCheck() == NO_ERROR) { + sensor_t const* list; + ssize_t count = dev.getSensorList(&list); + if (count > 0) { + ssize_t orientationIndex = -1; + bool hasGyro = false; + uint32_t virtualSensorsNeeds = + (1<<SENSOR_TYPE_GRAVITY) | + (1<<SENSOR_TYPE_LINEAR_ACCELERATION) | + (1<<SENSOR_TYPE_ROTATION_VECTOR); + + mLastEventSeen.setCapacity(count); + for (ssize_t i=0 ; i<count ; i++) { + registerSensor( new HardwareSensor(list[i]) ); + switch (list[i].type) { + case SENSOR_TYPE_ORIENTATION: + orientationIndex = i; + break; + case SENSOR_TYPE_GYROSCOPE: + hasGyro = true; + break; + case SENSOR_TYPE_GRAVITY: + case SENSOR_TYPE_LINEAR_ACCELERATION: + case SENSOR_TYPE_ROTATION_VECTOR: + virtualSensorsNeeds &= ~(1<<list[i].type); + break; + } + } + + // it's safe to instantiate the SensorFusion object here + // (it wants to be instantiated after h/w sensors have been + // registered) + const SensorFusion& fusion(SensorFusion::getInstance()); + + if (hasGyro) { + // Always instantiate Android's virtual sensors. Since they are + // instantiated behind sensors from the HAL, they won't + // interfere with applications, unless they looks specifically + // for them (by name). + + registerVirtualSensor( new RotationVectorSensor() ); + registerVirtualSensor( new GravitySensor(list, count) ); + registerVirtualSensor( new LinearAccelerationSensor(list, count) ); + + // these are optional + registerVirtualSensor( new OrientationSensor() ); + registerVirtualSensor( new CorrectedGyroSensor(list, count) ); + } + + // build the sensor list returned to users + mUserSensorList = mSensorList; + + if (hasGyro) { + // virtual debugging sensors are not added to mUserSensorList + registerVirtualSensor( new GyroDriftSensor() ); + } + + if (hasGyro && + (virtualSensorsNeeds & (1<<SENSOR_TYPE_ROTATION_VECTOR))) { + // if we have the fancy sensor fusion, and it's not provided by the + // HAL, use our own (fused) orientation sensor by removing the + // HAL supplied one form the user list. + if (orientationIndex >= 0) { + mUserSensorList.removeItemsAt(orientationIndex); + } + } + + // debugging sensor list + for (size_t i=0 ; i<mSensorList.size() ; i++) { + switch (mSensorList[i].getType()) { + case SENSOR_TYPE_GRAVITY: + case SENSOR_TYPE_LINEAR_ACCELERATION: + case SENSOR_TYPE_ROTATION_VECTOR: + if (strstr(mSensorList[i].getVendor().string(), "Google")) { + mUserSensorListDebug.add(mSensorList[i]); + } + break; + default: + mUserSensorListDebug.add(mSensorList[i]); + break; + } + } + + run("SensorService", PRIORITY_URGENT_DISPLAY); + mInitCheck = NO_ERROR; + } + } +} + +void SensorService::registerSensor(SensorInterface* s) +{ + sensors_event_t event; + memset(&event, 0, sizeof(event)); + + const Sensor sensor(s->getSensor()); + // add to the sensor list (returned to clients) + mSensorList.add(sensor); + // add to our handle->SensorInterface mapping + mSensorMap.add(sensor.getHandle(), s); + // create an entry in the mLastEventSeen array + mLastEventSeen.add(sensor.getHandle(), event); +} + +void SensorService::registerVirtualSensor(SensorInterface* s) +{ + registerSensor(s); + mVirtualSensorList.add( s ); +} + +SensorService::~SensorService() +{ + for (size_t i=0 ; i<mSensorMap.size() ; i++) + delete mSensorMap.valueAt(i); +} + +static const String16 sDump("android.permission.DUMP"); + +status_t SensorService::dump(int fd, const Vector<String16>& args) +{ + const size_t SIZE = 1024; + char buffer[SIZE]; + String8 result; + if (!PermissionCache::checkCallingPermission(sDump)) { + snprintf(buffer, SIZE, "Permission Denial: " + "can't dump SurfaceFlinger from pid=%d, uid=%d\n", + IPCThreadState::self()->getCallingPid(), + IPCThreadState::self()->getCallingUid()); + result.append(buffer); + } else { + Mutex::Autolock _l(mLock); + snprintf(buffer, SIZE, "Sensor List:\n"); + result.append(buffer); + for (size_t i=0 ; i<mSensorList.size() ; i++) { + const Sensor& s(mSensorList[i]); + const sensors_event_t& e(mLastEventSeen.valueFor(s.getHandle())); + snprintf(buffer, SIZE, + "%-48s| %-32s | 0x%08x | maxRate=%7.2fHz | " + "last=<%5.1f,%5.1f,%5.1f>\n", + s.getName().string(), + s.getVendor().string(), + s.getHandle(), + s.getMinDelay() ? (1000000.0f / s.getMinDelay()) : 0.0f, + e.data[0], e.data[1], e.data[2]); + result.append(buffer); + } + SensorFusion::getInstance().dump(result, buffer, SIZE); + SensorDevice::getInstance().dump(result, buffer, SIZE); + + snprintf(buffer, SIZE, "%d active connections\n", + mActiveConnections.size()); + result.append(buffer); + snprintf(buffer, SIZE, "Active sensors:\n"); + result.append(buffer); + for (size_t i=0 ; i<mActiveSensors.size() ; i++) { + int handle = mActiveSensors.keyAt(i); + snprintf(buffer, SIZE, "%s (handle=0x%08x, connections=%d)\n", + getSensorName(handle).string(), + handle, + mActiveSensors.valueAt(i)->getNumConnections()); + result.append(buffer); + } + } + write(fd, result.string(), result.size()); + return NO_ERROR; +} + +bool SensorService::threadLoop() +{ + ALOGD("nuSensorService thread starting..."); + + const size_t numEventMax = 16; + const size_t minBufferSize = numEventMax + numEventMax * mVirtualSensorList.size(); + sensors_event_t buffer[minBufferSize]; + sensors_event_t scratch[minBufferSize]; + SensorDevice& device(SensorDevice::getInstance()); + const size_t vcount = mVirtualSensorList.size(); + + ssize_t count; + do { + count = device.poll(buffer, numEventMax); + if (count<0) { + ALOGE("sensor poll failed (%s)", strerror(-count)); + break; + } + + recordLastValue(buffer, count); + + // handle virtual sensors + if (count && vcount) { + sensors_event_t const * const event = buffer; + const DefaultKeyedVector<int, SensorInterface*> virtualSensors( + getActiveVirtualSensors()); + const size_t activeVirtualSensorCount = virtualSensors.size(); + if (activeVirtualSensorCount) { + size_t k = 0; + SensorFusion& fusion(SensorFusion::getInstance()); + if (fusion.isEnabled()) { + for (size_t i=0 ; i<size_t(count) ; i++) { + fusion.process(event[i]); + } + } + for (size_t i=0 ; i<size_t(count) && k<minBufferSize ; i++) { + for (size_t j=0 ; j<activeVirtualSensorCount ; j++) { + if (count + k >= minBufferSize) { + ALOGE("buffer too small to hold all events: " + "count=%u, k=%u, size=%u", + count, k, minBufferSize); + break; + } + sensors_event_t out; + SensorInterface* si = virtualSensors.valueAt(j); + if (si->process(&out, event[i])) { + buffer[count + k] = out; + k++; + } + } + } + if (k) { + // record the last synthesized values + recordLastValue(&buffer[count], k); + count += k; + // sort the buffer by time-stamps + sortEventBuffer(buffer, count); + } + } + } + + // send our events to clients... + const SortedVector< wp<SensorEventConnection> > activeConnections( + getActiveConnections()); + size_t numConnections = activeConnections.size(); + for (size_t i=0 ; i<numConnections ; i++) { + sp<SensorEventConnection> connection( + activeConnections[i].promote()); + if (connection != 0) { + connection->sendEvents(buffer, count, scratch); + } + } + } while (count >= 0 || Thread::exitPending()); + + ALOGW("Exiting SensorService::threadLoop => aborting..."); + abort(); + return false; +} + +void SensorService::recordLastValue( + sensors_event_t const * buffer, size_t count) +{ + Mutex::Autolock _l(mLock); + + // record the last event for each sensor + int32_t prev = buffer[0].sensor; + for (size_t i=1 ; i<count ; i++) { + // record the last event of each sensor type in this buffer + int32_t curr = buffer[i].sensor; + if (curr != prev) { + mLastEventSeen.editValueFor(prev) = buffer[i-1]; + prev = curr; + } + } + mLastEventSeen.editValueFor(prev) = buffer[count-1]; +} + +void SensorService::sortEventBuffer(sensors_event_t* buffer, size_t count) +{ + struct compar { + static int cmp(void const* lhs, void const* rhs) { + sensors_event_t const* l = static_cast<sensors_event_t const*>(lhs); + sensors_event_t const* r = static_cast<sensors_event_t const*>(rhs); + return l->timestamp - r->timestamp; + } + }; + qsort(buffer, count, sizeof(sensors_event_t), compar::cmp); +} + +SortedVector< wp<SensorService::SensorEventConnection> > +SensorService::getActiveConnections() const +{ + Mutex::Autolock _l(mLock); + return mActiveConnections; +} + +DefaultKeyedVector<int, SensorInterface*> +SensorService::getActiveVirtualSensors() const +{ + Mutex::Autolock _l(mLock); + return mActiveVirtualSensors; +} + +String8 SensorService::getSensorName(int handle) const { + size_t count = mUserSensorList.size(); + for (size_t i=0 ; i<count ; i++) { + const Sensor& sensor(mUserSensorList[i]); + if (sensor.getHandle() == handle) { + return sensor.getName(); + } + } + String8 result("unknown"); + return result; +} + +Vector<Sensor> SensorService::getSensorList() +{ + char value[PROPERTY_VALUE_MAX]; + property_get("debug.sensors", value, "0"); + if (atoi(value)) { + return mUserSensorListDebug; + } + return mUserSensorList; +} + +sp<ISensorEventConnection> SensorService::createSensorEventConnection() +{ + sp<SensorEventConnection> result(new SensorEventConnection(this)); + return result; +} + +void SensorService::cleanupConnection(SensorEventConnection* c) +{ + Mutex::Autolock _l(mLock); + const wp<SensorEventConnection> connection(c); + size_t size = mActiveSensors.size(); + ALOGD_IF(DEBUG_CONNECTIONS, "%d active sensors", size); + for (size_t i=0 ; i<size ; ) { + int handle = mActiveSensors.keyAt(i); + if (c->hasSensor(handle)) { + ALOGD_IF(DEBUG_CONNECTIONS, "%i: disabling handle=0x%08x", i, handle); + SensorInterface* sensor = mSensorMap.valueFor( handle ); + ALOGE_IF(!sensor, "mSensorMap[handle=0x%08x] is null!", handle); + if (sensor) { + sensor->activate(c, false); + } + } + SensorRecord* rec = mActiveSensors.valueAt(i); + ALOGE_IF(!rec, "mActiveSensors[%d] is null (handle=0x%08x)!", i, handle); + ALOGD_IF(DEBUG_CONNECTIONS, + "removing connection %p for sensor[%d].handle=0x%08x", + c, i, handle); + + if (rec && rec->removeConnection(connection)) { + ALOGD_IF(DEBUG_CONNECTIONS, "... and it was the last connection"); + mActiveSensors.removeItemsAt(i, 1); + mActiveVirtualSensors.removeItem(handle); + delete rec; + size--; + } else { + i++; + } + } + mActiveConnections.remove(connection); +} + +status_t SensorService::enable(const sp<SensorEventConnection>& connection, + int handle) +{ + if (mInitCheck != NO_ERROR) + return mInitCheck; + + Mutex::Autolock _l(mLock); + SensorInterface* sensor = mSensorMap.valueFor(handle); + status_t err = sensor ? sensor->activate(connection.get(), true) : status_t(BAD_VALUE); + if (err == NO_ERROR) { + SensorRecord* rec = mActiveSensors.valueFor(handle); + if (rec == 0) { + rec = new SensorRecord(connection); + mActiveSensors.add(handle, rec); + if (sensor->isVirtual()) { + mActiveVirtualSensors.add(handle, sensor); + } + } else { + if (rec->addConnection(connection)) { + // this sensor is already activated, but we are adding a + // connection that uses it. Immediately send down the last + // known value of the requested sensor if it's not a + // "continuous" sensor. + if (sensor->getSensor().getMinDelay() == 0) { + sensors_event_t scratch; + sensors_event_t& event(mLastEventSeen.editValueFor(handle)); + if (event.version == sizeof(sensors_event_t)) { + connection->sendEvents(&event, 1); + } + } + } + } + if (err == NO_ERROR) { + // connection now active + if (connection->addSensor(handle)) { + // the sensor was added (which means it wasn't already there) + // so, see if this connection becomes active + if (mActiveConnections.indexOf(connection) < 0) { + mActiveConnections.add(connection); + } + } + } + } + return err; +} + +status_t SensorService::disable(const sp<SensorEventConnection>& connection, + int handle) +{ + if (mInitCheck != NO_ERROR) + return mInitCheck; + + status_t err = NO_ERROR; + Mutex::Autolock _l(mLock); + SensorRecord* rec = mActiveSensors.valueFor(handle); + if (rec) { + // see if this connection becomes inactive + connection->removeSensor(handle); + if (connection->hasAnySensor() == false) { + mActiveConnections.remove(connection); + } + // see if this sensor becomes inactive + if (rec->removeConnection(connection)) { + mActiveSensors.removeItem(handle); + mActiveVirtualSensors.removeItem(handle); + delete rec; + } + SensorInterface* sensor = mSensorMap.valueFor(handle); + err = sensor ? sensor->activate(connection.get(), false) : status_t(BAD_VALUE); + } + return err; +} + +status_t SensorService::setEventRate(const sp<SensorEventConnection>& connection, + int handle, nsecs_t ns) +{ + if (mInitCheck != NO_ERROR) + return mInitCheck; + + SensorInterface* sensor = mSensorMap.valueFor(handle); + if (!sensor) + return BAD_VALUE; + + if (ns < 0) + return BAD_VALUE; + + nsecs_t minDelayNs = sensor->getSensor().getMinDelayNs(); + if (ns < minDelayNs) { + ns = minDelayNs; + } + + if (ns < MINIMUM_EVENTS_PERIOD) + ns = MINIMUM_EVENTS_PERIOD; + + return sensor->setDelay(connection.get(), handle, ns); +} + +// --------------------------------------------------------------------------- + +SensorService::SensorRecord::SensorRecord( + const sp<SensorEventConnection>& connection) +{ + mConnections.add(connection); +} + +bool SensorService::SensorRecord::addConnection( + const sp<SensorEventConnection>& connection) +{ + if (mConnections.indexOf(connection) < 0) { + mConnections.add(connection); + return true; + } + return false; +} + +bool SensorService::SensorRecord::removeConnection( + const wp<SensorEventConnection>& connection) +{ + ssize_t index = mConnections.indexOf(connection); + if (index >= 0) { + mConnections.removeItemsAt(index, 1); + } + return mConnections.size() ? false : true; +} + +// --------------------------------------------------------------------------- + +SensorService::SensorEventConnection::SensorEventConnection( + const sp<SensorService>& service) + : mService(service), mChannel(new BitTube()) +{ +} + +SensorService::SensorEventConnection::~SensorEventConnection() +{ + ALOGD_IF(DEBUG_CONNECTIONS, "~SensorEventConnection(%p)", this); + mService->cleanupConnection(this); +} + +void SensorService::SensorEventConnection::onFirstRef() +{ +} + +bool SensorService::SensorEventConnection::addSensor(int32_t handle) { + Mutex::Autolock _l(mConnectionLock); + if (mSensorInfo.indexOf(handle) <= 0) { + mSensorInfo.add(handle); + return true; + } + return false; +} + +bool SensorService::SensorEventConnection::removeSensor(int32_t handle) { + Mutex::Autolock _l(mConnectionLock); + if (mSensorInfo.remove(handle) >= 0) { + return true; + } + return false; +} + +bool SensorService::SensorEventConnection::hasSensor(int32_t handle) const { + Mutex::Autolock _l(mConnectionLock); + return mSensorInfo.indexOf(handle) >= 0; +} + +bool SensorService::SensorEventConnection::hasAnySensor() const { + Mutex::Autolock _l(mConnectionLock); + return mSensorInfo.size() ? true : false; +} + +status_t SensorService::SensorEventConnection::sendEvents( + sensors_event_t const* buffer, size_t numEvents, + sensors_event_t* scratch) +{ + // filter out events not for this connection + size_t count = 0; + if (scratch) { + Mutex::Autolock _l(mConnectionLock); + size_t i=0; + while (i<numEvents) { + const int32_t curr = buffer[i].sensor; + if (mSensorInfo.indexOf(curr) >= 0) { + do { + scratch[count++] = buffer[i++]; + } while ((i<numEvents) && (buffer[i].sensor == curr)); + } else { + i++; + } + } + } else { + scratch = const_cast<sensors_event_t *>(buffer); + count = numEvents; + } + + // NOTE: ASensorEvent and sensors_event_t are the same type + ssize_t size = SensorEventQueue::write(mChannel, + reinterpret_cast<ASensorEvent const*>(scratch), count); + if (size == -EAGAIN) { + // the destination doesn't accept events anymore, it's probably + // full. For now, we just drop the events on the floor. + //ALOGW("dropping %d events on the floor", count); + return size; + } + + return size < 0 ? status_t(size) : status_t(NO_ERROR); +} + +sp<BitTube> SensorService::SensorEventConnection::getSensorChannel() const +{ + return mChannel; +} + +status_t SensorService::SensorEventConnection::enableDisable( + int handle, bool enabled) +{ + status_t err; + if (enabled) { + err = mService->enable(this, handle); + } else { + err = mService->disable(this, handle); + } + return err; +} + +status_t SensorService::SensorEventConnection::setEventRate( + int handle, nsecs_t ns) +{ + return mService->setEventRate(this, handle, ns); +} + +// --------------------------------------------------------------------------- +}; // namespace android + diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h new file mode 100644 index 0000000..54a76e8 --- /dev/null +++ b/services/sensorservice/SensorService.h @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_SENSOR_SERVICE_H +#define ANDROID_SENSOR_SERVICE_H + +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Vector.h> +#include <utils/SortedVector.h> +#include <utils/KeyedVector.h> +#include <utils/threads.h> +#include <utils/RefBase.h> + +#include <binder/BinderService.h> + +#include <gui/Sensor.h> +#include <gui/BitTube.h> +#include <gui/ISensorServer.h> +#include <gui/ISensorEventConnection.h> + +#include "SensorInterface.h" + +// --------------------------------------------------------------------------- + +#define DEBUG_CONNECTIONS false + +struct sensors_poll_device_t; +struct sensors_module_t; + +namespace android { +// --------------------------------------------------------------------------- + +class SensorService : + public BinderService<SensorService>, + public BnSensorServer, + protected Thread +{ + friend class BinderService<SensorService>; + + static const nsecs_t MINIMUM_EVENTS_PERIOD = 1000000; // 1000 Hz + + SensorService(); + virtual ~SensorService(); + + virtual void onFirstRef(); + + // Thread interface + virtual bool threadLoop(); + + // ISensorServer interface + virtual Vector<Sensor> getSensorList(); + virtual sp<ISensorEventConnection> createSensorEventConnection(); + virtual status_t dump(int fd, const Vector<String16>& args); + + + class SensorEventConnection : public BnSensorEventConnection { + virtual ~SensorEventConnection(); + virtual void onFirstRef(); + virtual sp<BitTube> getSensorChannel() const; + virtual status_t enableDisable(int handle, bool enabled); + virtual status_t setEventRate(int handle, nsecs_t ns); + + sp<SensorService> const mService; + sp<BitTube> const mChannel; + mutable Mutex mConnectionLock; + + // protected by SensorService::mLock + SortedVector<int> mSensorInfo; + + public: + SensorEventConnection(const sp<SensorService>& service); + + status_t sendEvents(sensors_event_t const* buffer, size_t count, + sensors_event_t* scratch = NULL); + bool hasSensor(int32_t handle) const; + bool hasAnySensor() const; + bool addSensor(int32_t handle); + bool removeSensor(int32_t handle); + }; + + class SensorRecord { + SortedVector< wp<SensorEventConnection> > mConnections; + public: + SensorRecord(const sp<SensorEventConnection>& connection); + bool addConnection(const sp<SensorEventConnection>& connection); + bool removeConnection(const wp<SensorEventConnection>& connection); + size_t getNumConnections() const { return mConnections.size(); } + }; + + SortedVector< wp<SensorEventConnection> > getActiveConnections() const; + DefaultKeyedVector<int, SensorInterface*> getActiveVirtualSensors() const; + + String8 getSensorName(int handle) const; + void recordLastValue(sensors_event_t const * buffer, size_t count); + static void sortEventBuffer(sensors_event_t* buffer, size_t count); + void registerSensor(SensorInterface* sensor); + void registerVirtualSensor(SensorInterface* sensor); + + // constants + Vector<Sensor> mSensorList; + Vector<Sensor> mUserSensorListDebug; + Vector<Sensor> mUserSensorList; + DefaultKeyedVector<int, SensorInterface*> mSensorMap; + Vector<SensorInterface *> mVirtualSensorList; + status_t mInitCheck; + + // protected by mLock + mutable Mutex mLock; + DefaultKeyedVector<int, SensorRecord*> mActiveSensors; + DefaultKeyedVector<int, SensorInterface*> mActiveVirtualSensors; + SortedVector< wp<SensorEventConnection> > mActiveConnections; + + // The size of this vector is constant, only the items are mutable + KeyedVector<int32_t, sensors_event_t> mLastEventSeen; + +public: + static char const* getServiceName() { return "sensorservice"; } + + void cleanupConnection(SensorEventConnection* connection); + status_t enable(const sp<SensorEventConnection>& connection, int handle); + status_t disable(const sp<SensorEventConnection>& connection, int handle); + status_t setEventRate(const sp<SensorEventConnection>& connection, int handle, nsecs_t ns); +}; + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_SENSOR_SERVICE_H diff --git a/services/sensorservice/mat.h b/services/sensorservice/mat.h new file mode 100644 index 0000000..a76fc91 --- /dev/null +++ b/services/sensorservice/mat.h @@ -0,0 +1,393 @@ +/* + * 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. + */ + +#ifndef ANDROID_MAT_H +#define ANDROID_MAT_H + +#include "vec.h" +#include "traits.h" + +// ----------------------------------------------------------------------- + +namespace android { + +template <typename TYPE, size_t C, size_t R> +class mat; + +namespace helpers { + +template <typename TYPE, size_t C, size_t R> +mat<TYPE, C, R>& doAssign( + mat<TYPE, C, R>& lhs, + typename TypeTraits<TYPE>::ParameterType rhs) { + for (size_t i=0 ; i<C ; i++) + for (size_t j=0 ; j<R ; j++) + lhs[i][j] = (i==j) ? rhs : 0; + return lhs; +} + +template <typename TYPE, size_t C, size_t R, size_t D> +mat<TYPE, C, R> PURE doMul( + const mat<TYPE, D, R>& lhs, + const mat<TYPE, C, D>& rhs) +{ + mat<TYPE, C, R> res; + for (size_t c=0 ; c<C ; c++) { + for (size_t r=0 ; r<R ; r++) { + TYPE v(0); + for (size_t k=0 ; k<D ; k++) { + v += lhs[k][r] * rhs[c][k]; + } + res[c][r] = v; + } + } + return res; +} + +template <typename TYPE, size_t R, size_t D> +vec<TYPE, R> PURE doMul( + const mat<TYPE, D, R>& lhs, + const vec<TYPE, D>& rhs) +{ + vec<TYPE, R> res; + for (size_t r=0 ; r<R ; r++) { + TYPE v(0); + for (size_t k=0 ; k<D ; k++) { + v += lhs[k][r] * rhs[k]; + } + res[r] = v; + } + return res; +} + +template <typename TYPE, size_t C, size_t R> +mat<TYPE, C, R> PURE doMul( + const vec<TYPE, R>& lhs, + const mat<TYPE, C, 1>& rhs) +{ + mat<TYPE, C, R> res; + for (size_t c=0 ; c<C ; c++) { + for (size_t r=0 ; r<R ; r++) { + res[c][r] = lhs[r] * rhs[c][0]; + } + } + return res; +} + +template <typename TYPE, size_t C, size_t R> +mat<TYPE, C, R> PURE doMul( + const mat<TYPE, C, R>& rhs, + typename TypeTraits<TYPE>::ParameterType v) +{ + mat<TYPE, C, R> res; + for (size_t c=0 ; c<C ; c++) { + for (size_t r=0 ; r<R ; r++) { + res[c][r] = rhs[c][r] * v; + } + } + return res; +} + +template <typename TYPE, size_t C, size_t R> +mat<TYPE, C, R> PURE doMul( + typename TypeTraits<TYPE>::ParameterType v, + const mat<TYPE, C, R>& rhs) +{ + mat<TYPE, C, R> res; + for (size_t c=0 ; c<C ; c++) { + for (size_t r=0 ; r<R ; r++) { + res[c][r] = v * rhs[c][r]; + } + } + return res; +} + + +}; // namespace helpers + +// ----------------------------------------------------------------------- + +template <typename TYPE, size_t C, size_t R> +class mat : public vec< vec<TYPE, R>, C > { + typedef typename TypeTraits<TYPE>::ParameterType pTYPE; + typedef vec< vec<TYPE, R>, C > base; +public: + // STL-like interface. + typedef TYPE value_type; + typedef TYPE& reference; + typedef TYPE const& const_reference; + typedef size_t size_type; + size_type size() const { return R*C; } + enum { ROWS = R, COLS = C }; + + + // ----------------------------------------------------------------------- + // default constructors + + mat() { } + mat(const mat& rhs) : base(rhs) { } + mat(const base& rhs) : base(rhs) { } + + // ----------------------------------------------------------------------- + // conversion constructors + + // sets the diagonal to the value, off-diagonal to zero + mat(pTYPE rhs) { + helpers::doAssign(*this, rhs); + } + + // ----------------------------------------------------------------------- + // Assignment + + mat& operator=(const mat& rhs) { + base::operator=(rhs); + return *this; + } + + mat& operator=(const base& rhs) { + base::operator=(rhs); + return *this; + } + + mat& operator=(pTYPE rhs) { + return helpers::doAssign(*this, rhs); + } + + // ----------------------------------------------------------------------- + // non-member function declaration and definition + + friend inline mat PURE operator + (const mat& lhs, const mat& rhs) { + return helpers::doAdd( + static_cast<const base&>(lhs), + static_cast<const base&>(rhs)); + } + friend inline mat PURE operator - (const mat& lhs, const mat& rhs) { + return helpers::doSub( + static_cast<const base&>(lhs), + static_cast<const base&>(rhs)); + } + + // matrix*matrix + template <size_t D> + friend mat PURE operator * ( + const mat<TYPE, D, R>& lhs, + const mat<TYPE, C, D>& rhs) { + return helpers::doMul(lhs, rhs); + } + + // matrix*vector + friend vec<TYPE, R> PURE operator * ( + const mat& lhs, const vec<TYPE, C>& rhs) { + return helpers::doMul(lhs, rhs); + } + + // vector*matrix + friend mat PURE operator * ( + const vec<TYPE, R>& lhs, const mat<TYPE, C, 1>& rhs) { + return helpers::doMul(lhs, rhs); + } + + // matrix*scalar + friend inline mat PURE operator * (const mat& lhs, pTYPE v) { + return helpers::doMul(lhs, v); + } + + // scalar*matrix + friend inline mat PURE operator * (pTYPE v, const mat& rhs) { + return helpers::doMul(v, rhs); + } + + // ----------------------------------------------------------------------- + // streaming operator to set the columns of the matrix: + // example: + // mat33_t m; + // m << v0 << v1 << v2; + + // column_builder<> stores the matrix and knows which column to set + template<size_t PREV_COLUMN> + struct column_builder { + mat& matrix; + column_builder(mat& matrix) : matrix(matrix) { } + }; + + // operator << is not a method of column_builder<> so we can + // overload it for unauthorized values (partial specialization + // not allowed in class-scope). + // we just set the column and return the next column_builder<> + template<size_t PREV_COLUMN> + friend column_builder<PREV_COLUMN+1> operator << ( + const column_builder<PREV_COLUMN>& lhs, + const vec<TYPE, R>& rhs) { + lhs.matrix[PREV_COLUMN+1] = rhs; + return column_builder<PREV_COLUMN+1>(lhs.matrix); + } + + // we return void here so we get a compile-time error if the + // user tries to set too many columns + friend void operator << ( + const column_builder<C-2>& lhs, + const vec<TYPE, R>& rhs) { + lhs.matrix[C-1] = rhs; + } + + // this is where the process starts. we set the first columns and + // return the next column_builder<> + column_builder<0> operator << (const vec<TYPE, R>& rhs) { + (*this)[0] = rhs; + return column_builder<0>(*this); + } +}; + +// Specialize column matrix so they're exactly equivalent to a vector +template <typename TYPE, size_t R> +class mat<TYPE, 1, R> : public vec<TYPE, R> { + typedef vec<TYPE, R> base; +public: + // STL-like interface. + typedef TYPE value_type; + typedef TYPE& reference; + typedef TYPE const& const_reference; + typedef size_t size_type; + size_type size() const { return R; } + enum { ROWS = R, COLS = 1 }; + + mat() { } + mat(const base& rhs) : base(rhs) { } + mat(const mat& rhs) : base(rhs) { } + mat(const TYPE& rhs) { helpers::doAssign(*this, rhs); } + mat& operator=(const mat& rhs) { base::operator=(rhs); return *this; } + mat& operator=(const base& rhs) { base::operator=(rhs); return *this; } + mat& operator=(const TYPE& rhs) { return helpers::doAssign(*this, rhs); } + // we only have one column, so ignore the index + const base& operator[](size_t) const { return *this; } + base& operator[](size_t) { return *this; } + void operator << (const vec<TYPE, R>& rhs) { base::operator[](0) = rhs; } +}; + +// ----------------------------------------------------------------------- +// matrix functions + +// transpose. this handles matrices of matrices +inline int PURE transpose(int v) { return v; } +inline float PURE transpose(float v) { return v; } +inline double PURE transpose(double v) { return v; } + +// Transpose a matrix +template <typename TYPE, size_t C, size_t R> +mat<TYPE, R, C> PURE transpose(const mat<TYPE, C, R>& m) { + mat<TYPE, R, C> r; + for (size_t i=0 ; i<R ; i++) + for (size_t j=0 ; j<C ; j++) + r[i][j] = transpose(m[j][i]); + return r; +} + +// Calculate the trace of a matrix +template <typename TYPE, size_t C> static TYPE trace(const mat<TYPE, C, C>& m) { + TYPE t; + for (size_t i=0 ; i<C ; i++) + t += m[i][i]; + return t; +} + +// Test positive-semidefiniteness of a matrix +template <typename TYPE, size_t C> +static bool isPositiveSemidefinite(const mat<TYPE, C, C>& m, TYPE tolerance) { + for (size_t i=0 ; i<C ; i++) + if (m[i][i] < 0) + return false; + + for (size_t i=0 ; i<C ; i++) + for (size_t j=i+1 ; j<C ; j++) + if (fabs(m[i][j] - m[j][i]) > tolerance) + return false; + + return true; +} + +// Transpose a vector +template < + template<typename T, size_t S> class VEC, + typename TYPE, + size_t SIZE +> +mat<TYPE, SIZE, 1> PURE transpose(const VEC<TYPE, SIZE>& v) { + mat<TYPE, SIZE, 1> r; + for (size_t i=0 ; i<SIZE ; i++) + r[i][0] = transpose(v[i]); + return r; +} + +// ----------------------------------------------------------------------- +// "dumb" matrix inversion +template<typename T, size_t N> +mat<T, N, N> PURE invert(const mat<T, N, N>& src) { + T t; + size_t swap; + mat<T, N, N> tmp(src); + mat<T, N, N> inverse(1); + + for (size_t i=0 ; i<N ; i++) { + // look for largest element in column + swap = i; + for (size_t j=i+1 ; j<N ; j++) { + if (fabs(tmp[j][i]) > fabs(tmp[i][i])) { + swap = j; + } + } + + if (swap != i) { + /* swap rows. */ + for (size_t k=0 ; k<N ; k++) { + t = tmp[i][k]; + tmp[i][k] = tmp[swap][k]; + tmp[swap][k] = t; + + t = inverse[i][k]; + inverse[i][k] = inverse[swap][k]; + inverse[swap][k] = t; + } + } + + t = 1 / tmp[i][i]; + for (size_t k=0 ; k<N ; k++) { + tmp[i][k] *= t; + inverse[i][k] *= t; + } + for (size_t j=0 ; j<N ; j++) { + if (j != i) { + t = tmp[j][i]; + for (size_t k=0 ; k<N ; k++) { + tmp[j][k] -= tmp[i][k] * t; + inverse[j][k] -= inverse[i][k] * t; + } + } + } + } + return inverse; +} + +// ----------------------------------------------------------------------- + +typedef mat<float, 2, 2> mat22_t; +typedef mat<float, 3, 3> mat33_t; +typedef mat<float, 4, 4> mat44_t; + +// ----------------------------------------------------------------------- + +}; // namespace android + +#endif /* ANDROID_MAT_H */ diff --git a/services/sensorservice/quat.h b/services/sensorservice/quat.h new file mode 100644 index 0000000..fea1afe --- /dev/null +++ b/services/sensorservice/quat.h @@ -0,0 +1,98 @@ +/* + * 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. + */ + +#ifndef ANDROID_QUAT_H +#define ANDROID_QUAT_H + +#include <math.h> + +#include "vec.h" +#include "mat.h" + +// ----------------------------------------------------------------------- +namespace android { +// ----------------------------------------------------------------------- + +template <typename TYPE> +mat<TYPE, 3, 3> quatToMatrix(const vec<TYPE, 4>& q) { + mat<TYPE, 3, 3> R; + TYPE q0(q.w); + TYPE q1(q.x); + TYPE q2(q.y); + TYPE q3(q.z); + TYPE sq_q1 = 2 * q1 * q1; + TYPE sq_q2 = 2 * q2 * q2; + TYPE sq_q3 = 2 * q3 * q3; + TYPE q1_q2 = 2 * q1 * q2; + TYPE q3_q0 = 2 * q3 * q0; + TYPE q1_q3 = 2 * q1 * q3; + TYPE q2_q0 = 2 * q2 * q0; + TYPE q2_q3 = 2 * q2 * q3; + TYPE q1_q0 = 2 * q1 * q0; + R[0][0] = 1 - sq_q2 - sq_q3; + R[0][1] = q1_q2 - q3_q0; + R[0][2] = q1_q3 + q2_q0; + R[1][0] = q1_q2 + q3_q0; + R[1][1] = 1 - sq_q1 - sq_q3; + R[1][2] = q2_q3 - q1_q0; + R[2][0] = q1_q3 - q2_q0; + R[2][1] = q2_q3 + q1_q0; + R[2][2] = 1 - sq_q1 - sq_q2; + return R; +} + +template <typename TYPE> +vec<TYPE, 4> matrixToQuat(const mat<TYPE, 3, 3>& R) { + // matrix to quaternion + + struct { + inline TYPE operator()(TYPE v) { + return v < 0 ? 0 : v; + } + } clamp; + + vec<TYPE, 4> q; + const float Hx = R[0].x; + const float My = R[1].y; + const float Az = R[2].z; + q.x = sqrtf( clamp( Hx - My - Az + 1) * 0.25f ); + q.y = sqrtf( clamp(-Hx + My - Az + 1) * 0.25f ); + q.z = sqrtf( clamp(-Hx - My + Az + 1) * 0.25f ); + q.w = sqrtf( clamp( Hx + My + Az + 1) * 0.25f ); + q.x = copysignf(q.x, R[2].y - R[1].z); + q.y = copysignf(q.y, R[0].z - R[2].x); + q.z = copysignf(q.z, R[1].x - R[0].y); + // guaranteed to be unit-quaternion + return q; +} + +template <typename TYPE> +vec<TYPE, 4> normalize_quat(const vec<TYPE, 4>& q) { + vec<TYPE, 4> r(q); + if (r.w < 0) { + r = -r; + } + return normalize(r); +} + +// ----------------------------------------------------------------------- + +typedef vec4_t quat_t; + +// ----------------------------------------------------------------------- +}; // namespace android + +#endif /* ANDROID_QUAT_H */ diff --git a/services/sensorservice/tests/Android.mk b/services/sensorservice/tests/Android.mk new file mode 100644 index 0000000..45296dd --- /dev/null +++ b/services/sensorservice/tests/Android.mk @@ -0,0 +1,14 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + sensorservicetest.cpp + +LOCAL_SHARED_LIBRARIES := \ + libcutils libutils libui libgui + +LOCAL_MODULE:= test-sensorservice + +LOCAL_MODULE_TAGS := optional + +include $(BUILD_EXECUTABLE) diff --git a/services/sensorservice/tests/sensorservicetest.cpp b/services/sensorservice/tests/sensorservicetest.cpp new file mode 100644 index 0000000..1025fa8 --- /dev/null +++ b/services/sensorservice/tests/sensorservicetest.cpp @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2010 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 <android/sensor.h> +#include <gui/Sensor.h> +#include <gui/SensorManager.h> +#include <gui/SensorEventQueue.h> +#include <utils/Looper.h> + +using namespace android; + +static nsecs_t sStartTime = 0; + + +int receiver(int fd, int events, void* data) +{ + sp<SensorEventQueue> q((SensorEventQueue*)data); + ssize_t n; + ASensorEvent buffer[8]; + + static nsecs_t oldTimeStamp = 0; + + while ((n = q->read(buffer, 8)) > 0) { + for (int i=0 ; i<n ; i++) { + float t; + if (oldTimeStamp) { + t = float(buffer[i].timestamp - oldTimeStamp) / s2ns(1); + } else { + t = float(buffer[i].timestamp - sStartTime) / s2ns(1); + } + oldTimeStamp = buffer[i].timestamp; + + if (buffer[i].type == Sensor::TYPE_ACCELEROMETER) { + printf("%lld\t%8f\t%8f\t%8f\t%f\n", + buffer[i].timestamp, + buffer[i].data[0], buffer[i].data[1], buffer[i].data[2], + 1.0/t); + } + + } + } + if (n<0 && n != -EAGAIN) { + printf("error reading events (%s)\n", strerror(-n)); + } + return 1; +} + + +int main(int argc, char** argv) +{ + SensorManager& mgr(SensorManager::getInstance()); + + Sensor const* const* list; + ssize_t count = mgr.getSensorList(&list); + printf("numSensors=%d\n", int(count)); + + sp<SensorEventQueue> q = mgr.createEventQueue(); + printf("queue=%p\n", q.get()); + + Sensor const* accelerometer = mgr.getDefaultSensor(Sensor::TYPE_ACCELEROMETER); + printf("accelerometer=%p (%s)\n", + accelerometer, accelerometer->getName().string()); + + sStartTime = systemTime(); + + q->enableSensor(accelerometer); + + q->setEventRate(accelerometer, ms2ns(10)); + + sp<Looper> loop = new Looper(false); + loop->addFd(q->getFd(), 0, ALOOPER_EVENT_INPUT, receiver, q.get()); + + do { + //printf("about to poll...\n"); + int32_t ret = loop->pollOnce(-1); + switch (ret) { + case ALOOPER_POLL_WAKE: + //("ALOOPER_POLL_WAKE\n"); + break; + case ALOOPER_POLL_CALLBACK: + //("ALOOPER_POLL_CALLBACK\n"); + break; + case ALOOPER_POLL_TIMEOUT: + printf("ALOOPER_POLL_TIMEOUT\n"); + break; + case ALOOPER_POLL_ERROR: + printf("ALOOPER_POLL_TIMEOUT\n"); + break; + default: + printf("ugh? poll returned %d\n", ret); + break; + } + } while (1); + + + return 0; +} diff --git a/services/sensorservice/traits.h b/services/sensorservice/traits.h new file mode 100644 index 0000000..da4c599 --- /dev/null +++ b/services/sensorservice/traits.h @@ -0,0 +1,118 @@ +/* + * 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. + */ + +#ifndef ANDROID_TRAITS_H +#define ANDROID_TRAITS_H + +// ----------------------------------------------------------------------- +// Typelists + +namespace android { + +// end-of-list marker +class NullType {}; + +// type-list node +template <typename T, typename U> +struct TypeList { + typedef T Head; + typedef U Tail; +}; + +// helpers to build typelists +#define TYPELIST_1(T1) TypeList<T1, NullType> +#define TYPELIST_2(T1, T2) TypeList<T1, TYPELIST_1(T2)> +#define TYPELIST_3(T1, T2, T3) TypeList<T1, TYPELIST_2(T2, T3)> +#define TYPELIST_4(T1, T2, T3, T4) TypeList<T1, TYPELIST_3(T2, T3, T4)> + +// typelists algorithms +namespace TL { +template <typename TList, typename T> struct IndexOf; + +template <typename T> +struct IndexOf<NullType, T> { + enum { value = -1 }; +}; + +template <typename T, typename Tail> +struct IndexOf<TypeList<T, Tail>, T> { + enum { value = 0 }; +}; + +template <typename Head, typename Tail, typename T> +struct IndexOf<TypeList<Head, Tail>, T> { +private: + enum { temp = IndexOf<Tail, T>::value }; +public: + enum { value = temp == -1 ? -1 : 1 + temp }; +}; + +}; // namespace TL + +// type selection based on a boolean +template <bool flag, typename T, typename U> +struct Select { + typedef T Result; +}; +template <typename T, typename U> +struct Select<false, T, U> { + typedef U Result; +}; + +// ----------------------------------------------------------------------- +// Type traits + +template <typename T> +class TypeTraits { + typedef TYPELIST_4( + unsigned char, unsigned short, + unsigned int, unsigned long int) UnsignedInts; + + typedef TYPELIST_4( + signed char, signed short, + signed int, signed long int) SignedInts; + + typedef TYPELIST_1( + bool) OtherInts; + + typedef TYPELIST_3( + float, double, long double) Floats; + + template<typename U> struct PointerTraits { + enum { result = false }; + typedef NullType PointeeType; + }; + template<typename U> struct PointerTraits<U*> { + enum { result = true }; + typedef U PointeeType; + }; + +public: + enum { isStdUnsignedInt = TL::IndexOf<UnsignedInts, T>::value >= 0 }; + enum { isStdSignedInt = TL::IndexOf<SignedInts, T>::value >= 0 }; + enum { isStdIntegral = TL::IndexOf<OtherInts, T>::value >= 0 || isStdUnsignedInt || isStdSignedInt }; + enum { isStdFloat = TL::IndexOf<Floats, T>::value >= 0 }; + enum { isPointer = PointerTraits<T>::result }; + enum { isStdArith = isStdIntegral || isStdFloat }; + + // best parameter type for given type + typedef typename Select<isStdArith || isPointer, T, const T&>::Result ParameterType; +}; + +// ----------------------------------------------------------------------- +}; // namespace android + +#endif /* ANDROID_TRAITS_H */ diff --git a/services/sensorservice/vec.h b/services/sensorservice/vec.h new file mode 100644 index 0000000..24f30ff --- /dev/null +++ b/services/sensorservice/vec.h @@ -0,0 +1,438 @@ +/* + * 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. + */ + +#ifndef ANDROID_VEC_H +#define ANDROID_VEC_H + +#include <math.h> + +#include <stdint.h> +#include <stddef.h> + +#include "traits.h" + +// ----------------------------------------------------------------------- + +#define PURE __attribute__((pure)) + +namespace android { + +// ----------------------------------------------------------------------- +// non-inline helpers + +template <typename TYPE, size_t SIZE> +class vec; + +template <typename TYPE, size_t SIZE> +class vbase; + +namespace helpers { + +template <typename T> inline T min(T a, T b) { return a<b ? a : b; } +template <typename T> inline T max(T a, T b) { return a>b ? a : b; } + +template < template<typename T, size_t S> class VEC, + typename TYPE, size_t SIZE, size_t S> +vec<TYPE, SIZE>& doAssign( + vec<TYPE, SIZE>& lhs, const VEC<TYPE, S>& rhs) { + const size_t minSize = min(SIZE, S); + const size_t maxSize = max(SIZE, S); + for (size_t i=0 ; i<minSize ; i++) + lhs[i] = rhs[i]; + for (size_t i=minSize ; i<maxSize ; i++) + lhs[i] = 0; + return lhs; +} + + +template < + template<typename T, size_t S> class VLHS, + template<typename T, size_t S> class VRHS, + typename TYPE, + size_t SIZE +> +VLHS<TYPE, SIZE> PURE doAdd( + const VLHS<TYPE, SIZE>& lhs, + const VRHS<TYPE, SIZE>& rhs) { + VLHS<TYPE, SIZE> r; + for (size_t i=0 ; i<SIZE ; i++) + r[i] = lhs[i] + rhs[i]; + return r; +} + +template < + template<typename T, size_t S> class VLHS, + template<typename T, size_t S> class VRHS, + typename TYPE, + size_t SIZE +> +VLHS<TYPE, SIZE> PURE doSub( + const VLHS<TYPE, SIZE>& lhs, + const VRHS<TYPE, SIZE>& rhs) { + VLHS<TYPE, SIZE> r; + for (size_t i=0 ; i<SIZE ; i++) + r[i] = lhs[i] - rhs[i]; + return r; +} + +template < + template<typename T, size_t S> class VEC, + typename TYPE, + size_t SIZE +> +VEC<TYPE, SIZE> PURE doMulScalar( + const VEC<TYPE, SIZE>& lhs, + typename TypeTraits<TYPE>::ParameterType rhs) { + VEC<TYPE, SIZE> r; + for (size_t i=0 ; i<SIZE ; i++) + r[i] = lhs[i] * rhs; + return r; +} + +template < + template<typename T, size_t S> class VEC, + typename TYPE, + size_t SIZE +> +VEC<TYPE, SIZE> PURE doScalarMul( + typename TypeTraits<TYPE>::ParameterType lhs, + const VEC<TYPE, SIZE>& rhs) { + VEC<TYPE, SIZE> r; + for (size_t i=0 ; i<SIZE ; i++) + r[i] = lhs * rhs[i]; + return r; +} + +}; // namespace helpers + +// ----------------------------------------------------------------------- +// Below we define the mathematical operators for vectors. +// We use template template arguments so we can generically +// handle the case where the right-hand-size and left-hand-side are +// different vector types (but with same value_type and size). +// This is needed for performance when using ".xy{z}" element access +// on vec<>. Without this, an extra conversion to vec<> would be needed. +// +// example: +// vec4_t a; +// vec3_t b; +// vec3_t c = a.xyz + b; +// +// "a.xyz + b" is a mixed-operation between a vbase<> and a vec<>, requiring +// a conversion of vbase<> to vec<>. The template gunk below avoids this, +// by allowing the addition on these different vector types directly +// + +template < + template<typename T, size_t S> class VLHS, + template<typename T, size_t S> class VRHS, + typename TYPE, + size_t SIZE +> +inline VLHS<TYPE, SIZE> PURE operator + ( + const VLHS<TYPE, SIZE>& lhs, + const VRHS<TYPE, SIZE>& rhs) { + return helpers::doAdd(lhs, rhs); +} + +template < + template<typename T, size_t S> class VLHS, + template<typename T, size_t S> class VRHS, + typename TYPE, + size_t SIZE +> +inline VLHS<TYPE, SIZE> PURE operator - ( + const VLHS<TYPE, SIZE>& lhs, + const VRHS<TYPE, SIZE>& rhs) { + return helpers::doSub(lhs, rhs); +} + +template < + template<typename T, size_t S> class VEC, + typename TYPE, + size_t SIZE +> +inline VEC<TYPE, SIZE> PURE operator * ( + const VEC<TYPE, SIZE>& lhs, + typename TypeTraits<TYPE>::ParameterType rhs) { + return helpers::doMulScalar(lhs, rhs); +} + +template < + template<typename T, size_t S> class VEC, + typename TYPE, + size_t SIZE +> +inline VEC<TYPE, SIZE> PURE operator * ( + typename TypeTraits<TYPE>::ParameterType lhs, + const VEC<TYPE, SIZE>& rhs) { + return helpers::doScalarMul(lhs, rhs); +} + + +template < + template<typename T, size_t S> class VLHS, + template<typename T, size_t S> class VRHS, + typename TYPE, + size_t SIZE +> +TYPE PURE dot_product( + const VLHS<TYPE, SIZE>& lhs, + const VRHS<TYPE, SIZE>& rhs) { + TYPE r(0); + for (size_t i=0 ; i<SIZE ; i++) + r += lhs[i] * rhs[i]; + return r; +} + +template < + template<typename T, size_t S> class V, + typename TYPE, + size_t SIZE +> +TYPE PURE length(const V<TYPE, SIZE>& v) { + return sqrt(dot_product(v, v)); +} + +template < + template<typename T, size_t S> class V, + typename TYPE, + size_t SIZE +> +TYPE PURE length_squared(const V<TYPE, SIZE>& v) { + return dot_product(v, v); +} + +template < + template<typename T, size_t S> class V, + typename TYPE, + size_t SIZE +> +V<TYPE, SIZE> PURE normalize(const V<TYPE, SIZE>& v) { + return v * (1/length(v)); +} + +template < + template<typename T, size_t S> class VLHS, + template<typename T, size_t S> class VRHS, + typename TYPE +> +VLHS<TYPE, 3> PURE cross_product( + const VLHS<TYPE, 3>& u, + const VRHS<TYPE, 3>& v) { + VLHS<TYPE, 3> r; + r.x = u.y*v.z - u.z*v.y; + r.y = u.z*v.x - u.x*v.z; + r.z = u.x*v.y - u.y*v.x; + return r; +} + + +template <typename TYPE, size_t SIZE> +vec<TYPE, SIZE> PURE operator - (const vec<TYPE, SIZE>& lhs) { + vec<TYPE, SIZE> r; + for (size_t i=0 ; i<SIZE ; i++) + r[i] = -lhs[i]; + return r; +} + +// ----------------------------------------------------------------------- + +// This our basic vector type, it just implements the data storage +// and accessors. + +template <typename TYPE, size_t SIZE> +struct vbase { + TYPE v[SIZE]; + inline const TYPE& operator[](size_t i) const { return v[i]; } + inline TYPE& operator[](size_t i) { return v[i]; } +}; +template<> struct vbase<float, 2> { + union { + float v[2]; + struct { float x, y; }; + struct { float s, t; }; + }; + inline const float& operator[](size_t i) const { return v[i]; } + inline float& operator[](size_t i) { return v[i]; } +}; +template<> struct vbase<float, 3> { + union { + float v[3]; + struct { float x, y, z; }; + struct { float s, t, r; }; + vbase<float, 2> xy; + vbase<float, 2> st; + }; + inline const float& operator[](size_t i) const { return v[i]; } + inline float& operator[](size_t i) { return v[i]; } +}; +template<> struct vbase<float, 4> { + union { + float v[4]; + struct { float x, y, z, w; }; + struct { float s, t, r, q; }; + vbase<float, 3> xyz; + vbase<float, 3> str; + vbase<float, 2> xy; + vbase<float, 2> st; + }; + inline const float& operator[](size_t i) const { return v[i]; } + inline float& operator[](size_t i) { return v[i]; } +}; + +// ----------------------------------------------------------------------- + +template <typename TYPE, size_t SIZE> +class vec : public vbase<TYPE, SIZE> +{ + typedef typename TypeTraits<TYPE>::ParameterType pTYPE; + typedef vbase<TYPE, SIZE> base; + +public: + // STL-like interface. + typedef TYPE value_type; + typedef TYPE& reference; + typedef TYPE const& const_reference; + typedef size_t size_type; + + typedef TYPE* iterator; + typedef TYPE const* const_iterator; + iterator begin() { return base::v; } + iterator end() { return base::v + SIZE; } + const_iterator begin() const { return base::v; } + const_iterator end() const { return base::v + SIZE; } + size_type size() const { return SIZE; } + + // ----------------------------------------------------------------------- + // default constructors + + vec() { } + vec(const vec& rhs) : base(rhs) { } + vec(const base& rhs) : base(rhs) { } + + // ----------------------------------------------------------------------- + // conversion constructors + + vec(pTYPE rhs) { + for (size_t i=0 ; i<SIZE ; i++) + base::operator[](i) = rhs; + } + + template < template<typename T, size_t S> class VEC, size_t S> + explicit vec(const VEC<TYPE, S>& rhs) { + helpers::doAssign(*this, rhs); + } + + explicit vec(TYPE const* array) { + for (size_t i=0 ; i<SIZE ; i++) + base::operator[](i) = array[i]; + } + + // ----------------------------------------------------------------------- + // Assignment + + vec& operator = (const vec& rhs) { + base::operator=(rhs); + return *this; + } + + vec& operator = (const base& rhs) { + base::operator=(rhs); + return *this; + } + + vec& operator = (pTYPE rhs) { + for (size_t i=0 ; i<SIZE ; i++) + base::operator[](i) = rhs; + return *this; + } + + template < template<typename T, size_t S> class VEC, size_t S> + vec& operator = (const VEC<TYPE, S>& rhs) { + return helpers::doAssign(*this, rhs); + } + + // ----------------------------------------------------------------------- + // operation-assignment + + vec& operator += (const vec& rhs); + vec& operator -= (const vec& rhs); + vec& operator *= (pTYPE rhs); + + // ----------------------------------------------------------------------- + // non-member function declaration and definition + // NOTE: we declare the non-member function as friend inside the class + // so that they are known to the compiler when the class is instantiated. + // This helps the compiler doing template argument deduction when the + // passed types are not identical. Essentially this helps with + // type conversion so that you can multiply a vec<float> by an scalar int + // (for instance). + + friend inline vec PURE operator + (const vec& lhs, const vec& rhs) { + return helpers::doAdd(lhs, rhs); + } + friend inline vec PURE operator - (const vec& lhs, const vec& rhs) { + return helpers::doSub(lhs, rhs); + } + friend inline vec PURE operator * (const vec& lhs, pTYPE v) { + return helpers::doMulScalar(lhs, v); + } + friend inline vec PURE operator * (pTYPE v, const vec& rhs) { + return helpers::doScalarMul(v, rhs); + } + friend inline TYPE PURE dot_product(const vec& lhs, const vec& rhs) { + return android::dot_product(lhs, rhs); + } +}; + +// ----------------------------------------------------------------------- + +template <typename TYPE, size_t SIZE> +vec<TYPE, SIZE>& vec<TYPE, SIZE>::operator += (const vec<TYPE, SIZE>& rhs) { + vec<TYPE, SIZE>& lhs(*this); + for (size_t i=0 ; i<SIZE ; i++) + lhs[i] += rhs[i]; + return lhs; +} + +template <typename TYPE, size_t SIZE> +vec<TYPE, SIZE>& vec<TYPE, SIZE>::operator -= (const vec<TYPE, SIZE>& rhs) { + vec<TYPE, SIZE>& lhs(*this); + for (size_t i=0 ; i<SIZE ; i++) + lhs[i] -= rhs[i]; + return lhs; +} + +template <typename TYPE, size_t SIZE> +vec<TYPE, SIZE>& vec<TYPE, SIZE>::operator *= (vec<TYPE, SIZE>::pTYPE rhs) { + vec<TYPE, SIZE>& lhs(*this); + for (size_t i=0 ; i<SIZE ; i++) + lhs[i] *= rhs; + return lhs; +} + +// ----------------------------------------------------------------------- + +typedef vec<float, 2> vec2_t; +typedef vec<float, 3> vec3_t; +typedef vec<float, 4> vec4_t; + +// ----------------------------------------------------------------------- + +}; // namespace android + +#endif /* ANDROID_VEC_H */ diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index 6f7a7e1..dd0dc16 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -2,13 +2,15 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ + Client.cpp \ + DdmConnection.cpp \ + DisplayDevice.cpp \ EventThread.cpp \ Layer.cpp \ LayerBase.cpp \ LayerDim.cpp \ LayerScreenshot.cpp \ - DisplayHardware/DisplayHardware.cpp \ - DisplayHardware/DisplayHardwareBase.cpp \ + DisplayHardware/FramebufferSurface.cpp \ DisplayHardware/HWComposer.cpp \ DisplayHardware/PowerHAL.cpp \ GLExtensions.cpp \ @@ -21,23 +23,24 @@ LOCAL_SRC_FILES:= \ LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\" LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -ifeq ($(TARGET_BOARD_PLATFORM), omap3) +ifeq ($(TARGET_BOARD_PLATFORM),omap3) LOCAL_CFLAGS += -DNO_RGBX_8888 endif -ifeq ($(TARGET_BOARD_PLATFORM), omap4) +ifeq ($(TARGET_BOARD_PLATFORM),omap4) LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY endif -ifeq ($(TARGET_BOARD_PLATFORM), s5pc110) +ifeq ($(TARGET_BOARD_PLATFORM),s5pc110) LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY LOCAL_CFLAGS += -DNEVER_DEFAULT_TO_ASYNC_MODE endif -ifeq ($(TARGET_DISABLE_TRIPLE_BUFFERING), true) +ifeq ($(TARGET_DISABLE_TRIPLE_BUFFERING),true) LOCAL_CFLAGS += -DTARGET_DISABLE_TRIPLE_BUFFERING endif LOCAL_SHARED_LIBRARIES := \ libcutils \ + libdl \ libhardware \ libutils \ libEGL \ @@ -46,13 +49,6 @@ LOCAL_SHARED_LIBRARIES := \ libui \ libgui -# this is only needed for DDMS debugging -ifneq ($(TARGET_BUILD_PDK), true) - LOCAL_SHARED_LIBRARIES += libdvm libandroid_runtime - LOCAL_CLFAGS += -DDDMS_DEBUGGING - LOCAL_SRC_FILES += DdmConnection.cpp -endif - LOCAL_MODULE:= libsurfaceflinger include $(BUILD_SHARED_LIBRARY) diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp new file mode 100644 index 0000000..d5d551e --- /dev/null +++ b/services/surfaceflinger/Client.cpp @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdint.h> +#include <sys/types.h> + +#include <binder/PermissionCache.h> + +#include <private/android_filesystem_config.h> + +#include "Client.h" +#include "Layer.h" +#include "LayerBase.h" +#include "SurfaceFlinger.h" + +namespace android { + +// --------------------------------------------------------------------------- + +const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"); + +// --------------------------------------------------------------------------- + +Client::Client(const sp<SurfaceFlinger>& flinger) + : mFlinger(flinger), mNameGenerator(1) +{ +} + +Client::~Client() +{ + const size_t count = mLayers.size(); + for (size_t i=0 ; i<count ; i++) { + sp<LayerBaseClient> layer(mLayers.valueAt(i).promote()); + if (layer != 0) { + mFlinger->removeLayer(layer); + } + } +} + +status_t Client::initCheck() const { + return NO_ERROR; +} + +size_t Client::attachLayer(const sp<LayerBaseClient>& layer) +{ + Mutex::Autolock _l(mLock); + size_t name = mNameGenerator++; + mLayers.add(name, layer); + return name; +} + +void Client::detachLayer(const LayerBaseClient* layer) +{ + Mutex::Autolock _l(mLock); + // we do a linear search here, because this doesn't happen often + const size_t count = mLayers.size(); + for (size_t i=0 ; i<count ; i++) { + if (mLayers.valueAt(i) == layer) { + mLayers.removeItemsAt(i, 1); + break; + } + } +} +sp<LayerBaseClient> Client::getLayerUser(int32_t i) const +{ + Mutex::Autolock _l(mLock); + sp<LayerBaseClient> lbc; + wp<LayerBaseClient> layer(mLayers.valueFor(i)); + if (layer != 0) { + lbc = layer.promote(); + ALOGE_IF(lbc==0, "getLayerUser(name=%d) is dead", int(i)); + } + return lbc; +} + + +status_t Client::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + // these must be checked + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + const int self_pid = getpid(); + if (CC_UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != 0)) { + // we're called from a different process, do the real check + if (!PermissionCache::checkCallingPermission(sAccessSurfaceFlinger)) + { + ALOGE("Permission Denial: " + "can't openGlobalTransaction pid=%d, uid=%d", pid, uid); + return PERMISSION_DENIED; + } + } + return BnSurfaceComposerClient::onTransact(code, data, reply, flags); +} + + +sp<ISurface> Client::createSurface( + ISurfaceComposerClient::surface_data_t* params, + const String8& name, + DisplayID display, uint32_t w, uint32_t h, PixelFormat format, + uint32_t flags) +{ + /* + * createSurface must be called from the GL thread so that it can + * have access to the GL context. + */ + + class MessageCreateLayer : public MessageBase { + sp<ISurface> result; + SurfaceFlinger* flinger; + ISurfaceComposerClient::surface_data_t* params; + Client* client; + const String8& name; + DisplayID display; + uint32_t w, h; + PixelFormat format; + uint32_t flags; + public: + MessageCreateLayer(SurfaceFlinger* flinger, + ISurfaceComposerClient::surface_data_t* params, + const String8& name, Client* client, + DisplayID display, uint32_t w, uint32_t h, PixelFormat format, + uint32_t flags) + : flinger(flinger), params(params), client(client), name(name), + display(display), w(w), h(h), format(format), flags(flags) + { + } + sp<ISurface> getResult() const { return result; } + virtual bool handler() { + result = flinger->createLayer(params, name, client, + display, w, h, format, flags); + return true; + } + }; + + sp<MessageBase> msg = new MessageCreateLayer(mFlinger.get(), + params, name, this, display, w, h, format, flags); + mFlinger->postMessageSync(msg); + return static_cast<MessageCreateLayer*>( msg.get() )->getResult(); +} +status_t Client::destroySurface(SurfaceID sid) { + return mFlinger->onLayerRemoved(this, sid); +} + +// --------------------------------------------------------------------------- +}; // namespace android diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h new file mode 100644 index 0000000..9bfee72 --- /dev/null +++ b/services/surfaceflinger/Client.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_SF_CLIENT_H +#define ANDROID_SF_CLIENT_H + +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Errors.h> +#include <utils/KeyedVector.h> +#include <utils/Mutex.h> + +#include <gui/ISurfaceComposerClient.h> + +namespace android { + +// --------------------------------------------------------------------------- + +class LayerBaseClient; +class SurfaceFlinger; + +// --------------------------------------------------------------------------- + +class Client : public BnSurfaceComposerClient +{ +public: + Client(const sp<SurfaceFlinger>& flinger); + ~Client(); + + status_t initCheck() const; + + // protected by SurfaceFlinger::mStateLock + size_t attachLayer(const sp<LayerBaseClient>& layer); + + void detachLayer(const LayerBaseClient* layer); + + sp<LayerBaseClient> getLayerUser(int32_t i) const; + +private: + // ISurfaceComposerClient interface + virtual sp<ISurface> createSurface( + surface_data_t* params, const String8& name, + DisplayID display, uint32_t w, uint32_t h,PixelFormat format, + uint32_t flags); + + virtual status_t destroySurface(SurfaceID surfaceId); + + virtual status_t onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); + + // constant + sp<SurfaceFlinger> mFlinger; + + // protected by mLock + DefaultKeyedVector< size_t, wp<LayerBaseClient> > mLayers; + size_t mNameGenerator; + + // thread-safe + mutable Mutex mLock; +}; + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_SF_CLIENT_H diff --git a/services/surfaceflinger/DdmConnection.cpp b/services/surfaceflinger/DdmConnection.cpp index 467a915..433b38e 100644 --- a/services/surfaceflinger/DdmConnection.cpp +++ b/services/surfaceflinger/DdmConnection.cpp @@ -14,16 +14,16 @@ * limitations under the License. */ -#include <android_runtime/AndroidRuntime.h> +#include <dlfcn.h> + +#include <cutils/log.h> #include "jni.h" #include "DdmConnection.h" -extern "C" jint Java_com_android_internal_util_WithFramework_registerNatives( - JNIEnv* env, jclass clazz); - namespace android { + void DdmConnection::start(const char* name) { JavaVM* vm; JNIEnv* env; @@ -40,12 +40,36 @@ void DdmConnection::start(const char* name) { args.nOptions = 1; args.ignoreUnrecognized = JNI_FALSE; + + void* libdvm_dso = dlopen("libdvm.so", RTLD_NOW); + ALOGE_IF(!libdvm_dso, "DdmConnection: %s", dlerror()); + + void* libandroid_runtime_dso = dlopen("libandroid_runtime.so", RTLD_NOW); + ALOGE_IF(!libandroid_runtime_dso, "DdmConnection: %s", dlerror()); + + if (!libdvm_dso || !libandroid_runtime_dso) { + goto error; + } + + jint (*JNI_CreateJavaVM)(JavaVM** p_vm, JNIEnv** p_env, void* vm_args); + JNI_CreateJavaVM = (typeof JNI_CreateJavaVM)dlsym(libdvm_dso, "JNI_CreateJavaVM"); + ALOGE_IF(!JNI_CreateJavaVM, "DdmConnection: %s", dlerror()); + + jint (*registerNatives)(JNIEnv* env, jclass clazz); + registerNatives = (typeof registerNatives)dlsym(libandroid_runtime_dso, + "Java_com_android_internal_util_WithFramework_registerNatives"); + ALOGE_IF(!registerNatives, "DdmConnection: %s", dlerror()); + + if (!JNI_CreateJavaVM || !registerNatives) { + goto error; + } + if (JNI_CreateJavaVM(&vm, &env, &args) == 0) { jclass startClass; jmethodID startMeth; // register native code - if (Java_com_android_internal_util_WithFramework_registerNatives(env, 0) == 0) { + if (registerNatives(env, 0) == 0) { // set our name by calling DdmHandleAppName.setAppName() startClass = env->FindClass("android/ddm/DdmHandleAppName"); if (startClass) { @@ -70,6 +94,15 @@ void DdmConnection::start(const char* name) { } } } + return; + +error: + if (libandroid_runtime_dso) { + dlclose(libandroid_runtime_dso); + } + if (libdvm_dso) { + dlclose(libdvm_dso); + } } }; // namespace android diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp new file mode 100644 index 0000000..2289444 --- /dev/null +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <math.h> + +#include <cutils/properties.h> + +#include <utils/RefBase.h> +#include <utils/Log.h> + +#include <ui/DisplayInfo.h> +#include <ui/PixelFormat.h> + +#include <gui/SurfaceTextureClient.h> + +#include <GLES/gl.h> +#include <EGL/egl.h> +#include <EGL/eglext.h> + +#include <hardware/gralloc.h> + +#include "DisplayHardware/FramebufferSurface.h" +#include "DisplayHardware/HWComposer.h" + +#include "DisplayDevice.h" +#include "GLExtensions.h" +#include "SurfaceFlinger.h" +#include "LayerBase.h" + +// ---------------------------------------------------------------------------- +using namespace android; +// ---------------------------------------------------------------------------- + +static __attribute__((noinline)) +void checkGLErrors() +{ + do { + // there could be more than one error flag + GLenum error = glGetError(); + if (error == GL_NO_ERROR) + break; + ALOGE("GL error 0x%04x", int(error)); + } while(true); +} + +// ---------------------------------------------------------------------------- + +/* + * Initialize the display to the specified values. + * + */ + +DisplayDevice::DisplayDevice( + const sp<SurfaceFlinger>& flinger, + int display, + const sp<ANativeWindow>& nativeWindow, + const sp<FramebufferSurface>& framebufferSurface, + EGLConfig config) + : mFlinger(flinger), + mId(display), + mNativeWindow(nativeWindow), + mFramebufferSurface(framebufferSurface), + mDisplay(EGL_NO_DISPLAY), + mSurface(EGL_NO_SURFACE), + mContext(EGL_NO_CONTEXT), + mDisplayWidth(), mDisplayHeight(), mFormat(), + mFlags(), + mPageFlipCount(), + mSecureLayerVisible(false), + mScreenAcquired(false), + mOrientation(), + mLayerStack(0) +{ + init(config); +} + +DisplayDevice::~DisplayDevice() { + if (mSurface != EGL_NO_SURFACE) { + eglDestroySurface(mDisplay, mSurface); + mSurface = EGL_NO_SURFACE; + } +} + +bool DisplayDevice::isValid() const { + return mFlinger != NULL; +} + +int DisplayDevice::getWidth() const { + return mDisplayWidth; +} + +int DisplayDevice::getHeight() const { + return mDisplayHeight; +} + +PixelFormat DisplayDevice::getFormat() const { + return mFormat; +} + +EGLSurface DisplayDevice::getEGLSurface() const { + return mSurface; +} + +void DisplayDevice::init(EGLConfig config) +{ + ANativeWindow* const window = mNativeWindow.get(); + + int format; + window->query(window, NATIVE_WINDOW_FORMAT, &format); + + /* + * Create our display's surface + */ + + EGLSurface surface; + EGLint w, h; + EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + surface = eglCreateWindowSurface(display, config, window, NULL); + eglQuerySurface(display, surface, EGL_WIDTH, &mDisplayWidth); + eglQuerySurface(display, surface, EGL_HEIGHT, &mDisplayHeight); + + mDisplay = display; + mSurface = surface; + mFormat = format; + mPageFlipCount = 0; + + // external displays are always considered enabled + mScreenAcquired = mId >= DisplayDevice::DISPLAY_ID_COUNT; + + // initialize the display orientation transform. + DisplayDevice::setOrientation(DisplayState::eOrientationDefault); +} + +uint32_t DisplayDevice::getPageFlipCount() const { + return mPageFlipCount; +} + +status_t DisplayDevice::compositionComplete() const { + if (mFramebufferSurface == NULL) { + return NO_ERROR; + } + return mFramebufferSurface->compositionComplete(); +} + +void DisplayDevice::flip(const Region& dirty) const +{ + checkGLErrors(); + + EGLDisplay dpy = mDisplay; + EGLSurface surface = mSurface; + +#ifdef EGL_ANDROID_swap_rectangle + if (mFlags & SWAP_RECTANGLE) { + const Region newDirty(dirty.intersect(bounds())); + const Rect b(newDirty.getBounds()); + eglSetSwapRectangleANDROID(dpy, surface, + b.left, b.top, b.width(), b.height()); + } +#endif + + mPageFlipCount++; +} + +uint32_t DisplayDevice::getFlags() const +{ + return mFlags; +} + +void DisplayDevice::dump(String8& res) const +{ + if (mFramebufferSurface != NULL) { + mFramebufferSurface->dump(res); + } +} + +void DisplayDevice::makeCurrent(const sp<const DisplayDevice>& hw, EGLContext ctx) { + EGLSurface sur = eglGetCurrentSurface(EGL_DRAW); + if (sur != hw->mSurface) { + EGLDisplay dpy = eglGetCurrentDisplay(); + eglMakeCurrent(dpy, hw->mSurface, hw->mSurface, ctx); + } +} + +// ---------------------------------------------------------------------------- + +void DisplayDevice::setVisibleLayersSortedByZ(const Vector< sp<LayerBase> >& layers) { + mVisibleLayersSortedByZ = layers; + mSecureLayerVisible = false; + size_t count = layers.size(); + for (size_t i=0 ; i<count ; i++) { + if (layers[i]->isSecure()) { + mSecureLayerVisible = true; + } + } +} + +Vector< sp<LayerBase> > DisplayDevice::getVisibleLayersSortedByZ() const { + return mVisibleLayersSortedByZ; +} + +bool DisplayDevice::getSecureLayerVisible() const { + return mSecureLayerVisible; +} + +Region DisplayDevice::getDirtyRegion(bool repaintEverything) const { + Region dirty; + const Transform& planeTransform(mGlobalTransform); + if (repaintEverything) { + dirty.set(getBounds()); + } else { + dirty = planeTransform.transform(this->dirtyRegion); + dirty.andSelf(getBounds()); + } + return dirty; +} + +// ---------------------------------------------------------------------------- + +bool DisplayDevice::canDraw() const { + return mScreenAcquired; +} + +void DisplayDevice::releaseScreen() const { + mScreenAcquired = false; +} + +void DisplayDevice::acquireScreen() const { + mScreenAcquired = true; +} + +bool DisplayDevice::isScreenAcquired() const { + return mScreenAcquired; +} + +// ---------------------------------------------------------------------------- + +void DisplayDevice::setLayerStack(uint32_t stack) { + mLayerStack = stack; + dirtyRegion.set(bounds()); +} + +// ---------------------------------------------------------------------------- + +status_t DisplayDevice::orientationToTransfrom( + int orientation, int w, int h, Transform* tr) +{ + uint32_t flags = 0; + switch (orientation) { + case DisplayState::eOrientationDefault: + flags = Transform::ROT_0; + break; + case DisplayState::eOrientation90: + flags = Transform::ROT_90; + break; + case DisplayState::eOrientation180: + flags = Transform::ROT_180; + break; + case DisplayState::eOrientation270: + flags = Transform::ROT_270; + break; + default: + return BAD_VALUE; + } + tr->set(flags, w, h); + return NO_ERROR; +} + +status_t DisplayDevice::setOrientation(int orientation) { + int w = mDisplayWidth; + int h = mDisplayHeight; + + DisplayDevice::orientationToTransfrom( + orientation, w, h, &mGlobalTransform); + if (orientation & DisplayState::eOrientationSwapMask) { + int tmp = w; + w = h; + h = tmp; + } + mOrientation = orientation; + dirtyRegion.set(bounds()); + return NO_ERROR; +} diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h new file mode 100644 index 0000000..9790699 --- /dev/null +++ b/services/surfaceflinger/DisplayDevice.h @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_DISPLAY_DEVICE_H +#define ANDROID_DISPLAY_DEVICE_H + +#include <stdlib.h> + +#include <ui/PixelFormat.h> +#include <ui/Region.h> + +#include <EGL/egl.h> +#include <EGL/eglext.h> + +#include <utils/Mutex.h> +#include <utils/Timers.h> + +#include "Transform.h" + +struct ANativeWindow; + +namespace android { + +class DisplayInfo; +class FramebufferSurface; +class LayerBase; +class SurfaceFlinger; + +class DisplayDevice : public LightRefBase<DisplayDevice> +{ +public: + // region in layer-stack space + mutable Region dirtyRegion; + // region in screen space + mutable Region swapRegion; + // region in screen space + Region undefinedRegion; + + enum { + DISPLAY_ID_MAIN = 0, + DISPLAY_ID_HDMI = 1, + DISPLAY_ID_COUNT + }; + + enum { + PARTIAL_UPDATES = 0x00020000, // video driver feature + SWAP_RECTANGLE = 0x00080000, + }; + + DisplayDevice( + const sp<SurfaceFlinger>& flinger, + int dpy, + const sp<ANativeWindow>& nativeWindow, + const sp<FramebufferSurface>& framebufferSurface, + EGLConfig config); + + ~DisplayDevice(); + + // whether this is a valid object. An invalid DisplayDevice is returned + // when an non existing id is requested + bool isValid() const; + + // Flip the front and back buffers if the back buffer is "dirty". Might + // be instantaneous, might involve copying the frame buffer around. + void flip(const Region& dirty) const; + + int getWidth() const; + int getHeight() const; + PixelFormat getFormat() const; + uint32_t getFlags() const; + + EGLSurface getEGLSurface() const; + + void setVisibleLayersSortedByZ(const Vector< sp<LayerBase> >& layers); + Vector< sp<LayerBase> > getVisibleLayersSortedByZ() const; + bool getSecureLayerVisible() const; + Region getDirtyRegion(bool repaintEverything) const; + + status_t setOrientation(int orientation); + void setLayerStack(uint32_t stack); + + int getOrientation() const { return mOrientation; } + const Transform& getTransform() const { return mGlobalTransform; } + uint32_t getLayerStack() const { return mLayerStack; } + int32_t getDisplayId() const { return mId; } + + status_t compositionComplete() const; + + Rect getBounds() const { + return Rect(mDisplayWidth, mDisplayHeight); + } + inline Rect bounds() const { return getBounds(); } + + static void makeCurrent(const sp<const DisplayDevice>& hw, EGLContext ctx); + + /* ------------------------------------------------------------------------ + * blank / unplank management + */ + void releaseScreen() const; + void acquireScreen() const; + bool isScreenAcquired() const; + bool canDraw() const; + + /* ------------------------------------------------------------------------ + * Debugging + */ + uint32_t getPageFlipCount() const; + void dump(String8& res) const; + + inline bool operator < (const DisplayDevice& rhs) const { + return mId < rhs.mId; + } + +private: + void init(EGLConfig config); + + /* + * Constants, set during initialization + */ + sp<SurfaceFlinger> mFlinger; + int32_t mId; + + // ANativeWindow this display is rendering into + sp<ANativeWindow> mNativeWindow; + + // set if mNativeWindow is a FramebufferSurface + sp<FramebufferSurface> mFramebufferSurface; + + EGLDisplay mDisplay; + EGLSurface mSurface; + EGLContext mContext; + int mDisplayWidth; + int mDisplayHeight; + PixelFormat mFormat; + uint32_t mFlags; + mutable uint32_t mPageFlipCount; + + /* + * Can only accessed from the main thread, these members + * don't need synchronization. + */ + + // list of visible layers on that display + Vector< sp<LayerBase> > mVisibleLayersSortedByZ; + + // Whether we have a visible secure layer on this display + bool mSecureLayerVisible; + + // Whether the screen is blanked; + mutable int mScreenAcquired; + + + /* + * Transaction state + */ + static status_t orientationToTransfrom(int orientation, int w, int h, + Transform* tr); + Transform mGlobalTransform; + int mOrientation; + uint32_t mLayerStack; +}; + +}; // namespace android + +#endif // ANDROID_DISPLAY_DEVICE_H diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp deleted file mode 100644 index bb93215..0000000 --- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp +++ /dev/null @@ -1,481 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <math.h> - -#include <cutils/properties.h> - -#include <utils/RefBase.h> -#include <utils/Log.h> - -#include <ui/PixelFormat.h> -#include <ui/FramebufferNativeWindow.h> - -#include <GLES/gl.h> -#include <EGL/egl.h> -#include <EGL/eglext.h> - -#include "DisplayHardware/DisplayHardware.h" - -#include <hardware/gralloc.h> - -#include "DisplayHardwareBase.h" -#include "GLExtensions.h" -#include "HWComposer.h" -#include "SurfaceFlinger.h" - -using namespace android; - - -static __attribute__((noinline)) -void checkGLErrors() -{ - do { - // there could be more than one error flag - GLenum error = glGetError(); - if (error == GL_NO_ERROR) - break; - ALOGE("GL error 0x%04x", int(error)); - } while(true); -} - -static __attribute__((noinline)) -void checkEGLErrors(const char* token) -{ - struct EGLUtils { - static const char *strerror(EGLint err) { - switch (err){ - case EGL_SUCCESS: return "EGL_SUCCESS"; - case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED"; - case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS"; - case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC"; - case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE"; - case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG"; - case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT"; - case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE"; - case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY"; - case EGL_BAD_MATCH: return "EGL_BAD_MATCH"; - case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP"; - case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW"; - case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER"; - case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE"; - case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST"; - default: return "UNKNOWN"; - } - } - }; - - EGLint error = eglGetError(); - if (error && error != EGL_SUCCESS) { - ALOGE("%s: EGL error 0x%04x (%s)", - token, int(error), EGLUtils::strerror(error)); - } -} - -/* - * Initialize the display to the specified values. - * - */ - -DisplayHardware::DisplayHardware( - const sp<SurfaceFlinger>& flinger, - uint32_t dpy) - : DisplayHardwareBase(flinger, dpy), - mFlinger(flinger), mFlags(0), mHwc(0) -{ - init(dpy); -} - -DisplayHardware::~DisplayHardware() -{ - fini(); -} - -float DisplayHardware::getDpiX() const { return mDpiX; } -float DisplayHardware::getDpiY() const { return mDpiY; } -float DisplayHardware::getDensity() const { return mDensity; } -float DisplayHardware::getRefreshRate() const { return mRefreshRate; } -int DisplayHardware::getWidth() const { return mWidth; } -int DisplayHardware::getHeight() const { return mHeight; } -PixelFormat DisplayHardware::getFormat() const { return mFormat; } -uint32_t DisplayHardware::getMaxTextureSize() const { return mMaxTextureSize; } - -uint32_t DisplayHardware::getMaxViewportDims() const { - return mMaxViewportDims[0] < mMaxViewportDims[1] ? - mMaxViewportDims[0] : mMaxViewportDims[1]; -} - -static status_t selectConfigForPixelFormat( - EGLDisplay dpy, - EGLint const* attrs, - PixelFormat format, - EGLConfig* outConfig) -{ - EGLConfig config = NULL; - EGLint numConfigs = -1, n=0; - eglGetConfigs(dpy, NULL, 0, &numConfigs); - EGLConfig* const configs = new EGLConfig[numConfigs]; - eglChooseConfig(dpy, attrs, configs, numConfigs, &n); - for (int i=0 ; i<n ; i++) { - EGLint nativeVisualId = 0; - eglGetConfigAttrib(dpy, configs[i], EGL_NATIVE_VISUAL_ID, &nativeVisualId); - if (nativeVisualId>0 && format == nativeVisualId) { - *outConfig = configs[i]; - delete [] configs; - return NO_ERROR; - } - } - delete [] configs; - return NAME_NOT_FOUND; -} - - -void DisplayHardware::init(uint32_t dpy) -{ - mNativeWindow = new FramebufferNativeWindow(); - framebuffer_device_t const * fbDev = mNativeWindow->getDevice(); - if (!fbDev) { - ALOGE("Display subsystem failed to initialize. check logs. exiting..."); - exit(0); - } - - int format; - ANativeWindow const * const window = mNativeWindow.get(); - window->query(window, NATIVE_WINDOW_FORMAT, &format); - mDpiX = mNativeWindow->xdpi; - mDpiY = mNativeWindow->ydpi; - mRefreshRate = fbDev->fps; - - if (mDpiX == 0 || mDpiY == 0) { - ALOGE("invalid screen resolution from fb HAL (xdpi=%f, ydpi=%f), " - "defaulting to 160 dpi", mDpiX, mDpiY); - mDpiX = mDpiY = 160; - } - - class Density { - static int getDensityFromProperty(char const* propName) { - char property[PROPERTY_VALUE_MAX]; - int density = 0; - if (property_get(propName, property, NULL) > 0) { - density = atoi(property); - } - return density; - } - public: - static int getEmuDensity() { - return getDensityFromProperty("qemu.sf.lcd_density"); } - static int getBuildDensity() { - return getDensityFromProperty("ro.sf.lcd_density"); } - }; - - - // The density of the device is provided by a build property - mDensity = Density::getBuildDensity() / 160.0f; - - if (mDensity == 0) { - // the build doesn't provide a density -- this is wrong! - // use xdpi instead - ALOGE("ro.sf.lcd_density must be defined as a build property"); - mDensity = mDpiX / 160.0f; - } - - if (Density::getEmuDensity()) { - // if "qemu.sf.lcd_density" is specified, it overrides everything - mDpiX = mDpiY = mDensity = Density::getEmuDensity(); - mDensity /= 160.0f; - } - - - - /* FIXME: this is a temporary HACK until we are able to report the refresh rate - * properly from the HAL. The WindowManagerService now relies on this value. - */ -#ifndef REFRESH_RATE - mRefreshRate = fbDev->fps; -#else - mRefreshRate = REFRESH_RATE; -#warning "refresh rate set via makefile to REFRESH_RATE" -#endif - - mRefreshPeriod = nsecs_t(1e9 / mRefreshRate); - - EGLint w, h, dummy; - EGLint numConfigs=0; - EGLSurface surface; - EGLContext context; - EGLBoolean result; - status_t err; - - // initialize EGL - EGLint attribs[] = { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_NONE, 0, - EGL_NONE - }; - - // debug: disable h/w rendering - char property[PROPERTY_VALUE_MAX]; - if (property_get("debug.sf.hw", property, NULL) > 0) { - if (atoi(property) == 0) { - ALOGW("H/W composition disabled"); - attribs[2] = EGL_CONFIG_CAVEAT; - attribs[3] = EGL_SLOW_CONFIG; - } - } - - // TODO: all the extensions below should be queried through - // eglGetProcAddress(). - - EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); - eglInitialize(display, NULL, NULL); - eglGetConfigs(display, NULL, 0, &numConfigs); - - EGLConfig config = NULL; - err = selectConfigForPixelFormat(display, attribs, format, &config); - ALOGE_IF(err, "couldn't find an EGLConfig matching the screen format"); - - EGLint r,g,b,a; - eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r); - eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g); - eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b); - eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a); - - if (mNativeWindow->isUpdateOnDemand()) { - mFlags |= PARTIAL_UPDATES; - } - - if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy) == EGL_TRUE) { - if (dummy == EGL_SLOW_CONFIG) - mFlags |= SLOW_CONFIG; - } - - /* - * Create our main surface - */ - - surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL); - eglQuerySurface(display, surface, EGL_WIDTH, &mWidth); - eglQuerySurface(display, surface, EGL_HEIGHT, &mHeight); - - if (mFlags & PARTIAL_UPDATES) { - // if we have partial updates, we definitely don't need to - // preserve the backbuffer, which may be costly. - eglSurfaceAttrib(display, surface, - EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED); - } - - /* - * Create our OpenGL ES context - */ - - EGLint contextAttributes[] = { -#ifdef EGL_IMG_context_priority -#ifdef HAS_CONTEXT_PRIORITY -#warning "using EGL_IMG_context_priority" - EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG, -#endif -#endif - EGL_NONE, EGL_NONE - }; - context = eglCreateContext(display, config, NULL, contextAttributes); - - mDisplay = display; - mConfig = config; - mSurface = surface; - mContext = context; - mFormat = fbDev->format; - mPageFlipCount = 0; - - /* - * Gather OpenGL ES extensions - */ - - result = eglMakeCurrent(display, surface, surface, context); - if (!result) { - ALOGE("Couldn't create a working GLES context. check logs. exiting..."); - exit(0); - } - - GLExtensions& extensions(GLExtensions::getInstance()); - extensions.initWithGLStrings( - glGetString(GL_VENDOR), - glGetString(GL_RENDERER), - glGetString(GL_VERSION), - glGetString(GL_EXTENSIONS), - eglQueryString(display, EGL_VENDOR), - eglQueryString(display, EGL_VERSION), - eglQueryString(display, EGL_EXTENSIONS)); - - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); - glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims); - - ALOGI("EGL informations:"); - ALOGI("# of configs : %d", numConfigs); - ALOGI("vendor : %s", extensions.getEglVendor()); - ALOGI("version : %s", extensions.getEglVersion()); - ALOGI("extensions: %s", extensions.getEglExtension()); - ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported"); - ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config); - - ALOGI("OpenGL informations:"); - ALOGI("vendor : %s", extensions.getVendor()); - ALOGI("renderer : %s", extensions.getRenderer()); - ALOGI("version : %s", extensions.getVersion()); - ALOGI("extensions: %s", extensions.getExtension()); - ALOGI("GL_MAX_TEXTURE_SIZE = %d", mMaxTextureSize); - ALOGI("GL_MAX_VIEWPORT_DIMS = %d x %d", mMaxViewportDims[0], mMaxViewportDims[1]); - ALOGI("flags = %08x", mFlags); - - // Unbind the context from this thread - eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - - - // initialize the H/W composer - mHwc = new HWComposer(mFlinger, *this, mRefreshPeriod); - if (mHwc->initCheck() == NO_ERROR) { - mHwc->setFrameBuffer(mDisplay, mSurface); - } -} - -void DisplayHardware::setVSyncHandler(const sp<VSyncHandler>& handler) { - Mutex::Autolock _l(mLock); - mVSyncHandler = handler; -} - -void DisplayHardware::eventControl(int event, int enabled) { - if (event == EVENT_VSYNC) { - mPowerHAL.vsyncHint(enabled); - } - mHwc->eventControl(event, enabled); -} - -void DisplayHardware::onVSyncReceived(int dpy, nsecs_t timestamp) { - sp<VSyncHandler> handler; - { // scope for the lock - Mutex::Autolock _l(mLock); - mLastHwVSync = timestamp; - if (mVSyncHandler != NULL) { - handler = mVSyncHandler.promote(); - } - } - - if (handler != NULL) { - handler->onVSyncReceived(dpy, timestamp); - } -} - -HWComposer& DisplayHardware::getHwComposer() const { - return *mHwc; -} - -/* - * Clean up. Throw out our local state. - * - * (It's entirely possible we'll never get here, since this is meant - * for real hardware, which doesn't restart.) - */ - -void DisplayHardware::fini() -{ - eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - eglTerminate(mDisplay); -} - -void DisplayHardware::releaseScreen() const -{ - DisplayHardwareBase::releaseScreen(); - if (mHwc->initCheck() == NO_ERROR) { - mHwc->release(); - } -} - -void DisplayHardware::acquireScreen() const -{ - DisplayHardwareBase::acquireScreen(); -} - -uint32_t DisplayHardware::getPageFlipCount() const { - return mPageFlipCount; -} - -nsecs_t DisplayHardware::getRefreshTimestamp() const { - // this returns the last refresh timestamp. - // if the last one is not available, we estimate it based on - // the refresh period and whatever closest timestamp we have. - Mutex::Autolock _l(mLock); - nsecs_t now = systemTime(CLOCK_MONOTONIC); - return now - ((now - mLastHwVSync) % mRefreshPeriod); -} - -nsecs_t DisplayHardware::getRefreshPeriod() const { - return mRefreshPeriod; -} - -status_t DisplayHardware::compositionComplete() const { - return mNativeWindow->compositionComplete(); -} - -void DisplayHardware::flip(const Region& dirty) const -{ - checkGLErrors(); - - EGLDisplay dpy = mDisplay; - EGLSurface surface = mSurface; - -#ifdef EGL_ANDROID_swap_rectangle - if (mFlags & SWAP_RECTANGLE) { - const Region newDirty(dirty.intersect(bounds())); - const Rect b(newDirty.getBounds()); - eglSetSwapRectangleANDROID(dpy, surface, - b.left, b.top, b.width(), b.height()); - } -#endif - - if (mFlags & PARTIAL_UPDATES) { - mNativeWindow->setUpdateRectangle(dirty.getBounds()); - } - - mPageFlipCount++; - - if (mHwc->initCheck() == NO_ERROR) { - mHwc->commit(); - } else { - eglSwapBuffers(dpy, surface); - } - checkEGLErrors("eglSwapBuffers"); - - // for debugging - //glClearColor(1,0,0,0); - //glClear(GL_COLOR_BUFFER_BIT); -} - -uint32_t DisplayHardware::getFlags() const -{ - return mFlags; -} - -void DisplayHardware::makeCurrent() const -{ - eglMakeCurrent(mDisplay, mSurface, mSurface, mContext); -} - -void DisplayHardware::dump(String8& res) const -{ - mNativeWindow->dump(res); -} diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h deleted file mode 100644 index 0604031..0000000 --- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_DISPLAY_HARDWARE_H -#define ANDROID_DISPLAY_HARDWARE_H - -#include <stdlib.h> - -#include <ui/PixelFormat.h> -#include <ui/Region.h> - -#include <GLES/gl.h> -#include <GLES/glext.h> -#include <EGL/egl.h> -#include <EGL/eglext.h> - -#include "GLExtensions.h" - -#include "DisplayHardware/DisplayHardwareBase.h" -#include "HWComposer.h" -#include "PowerHAL.h" - -namespace android { - -class FramebufferNativeWindow; - -class DisplayHardware : - public DisplayHardwareBase, - public HWComposer::EventHandler -{ -public: - - class VSyncHandler : virtual public RefBase { - friend class DisplayHardware; - virtual void onVSyncReceived(int dpy, nsecs_t timestamp) = 0; - protected: - virtual ~VSyncHandler() {} - }; - - enum { - COPY_BITS_EXTENSION = 0x00000008, - PARTIAL_UPDATES = 0x00020000, // video driver feature - SLOW_CONFIG = 0x00040000, // software - SWAP_RECTANGLE = 0x00080000, - }; - - DisplayHardware( - const sp<SurfaceFlinger>& flinger, - uint32_t displayIndex); - - virtual ~DisplayHardware(); - - void releaseScreen() const; - void acquireScreen() const; - - // Flip the front and back buffers if the back buffer is "dirty". Might - // be instantaneous, might involve copying the frame buffer around. - void flip(const Region& dirty) const; - - float getDpiX() const; - float getDpiY() const; - float getRefreshRate() const; - float getDensity() const; - int getWidth() const; - int getHeight() const; - PixelFormat getFormat() const; - uint32_t getFlags() const; - uint32_t getMaxTextureSize() const; - uint32_t getMaxViewportDims() const; - nsecs_t getRefreshPeriod() const; - nsecs_t getRefreshTimestamp() const; - void makeCurrent() const; - - - void setVSyncHandler(const sp<VSyncHandler>& handler); - - enum { - EVENT_VSYNC = HWC_EVENT_VSYNC - }; - - void eventControl(int event, int enabled); - - - uint32_t getPageFlipCount() const; - EGLDisplay getEGLDisplay() const { return mDisplay; } - - void dump(String8& res) const; - - // Hardware Composer - HWComposer& getHwComposer() const; - - status_t compositionComplete() const; - - Rect getBounds() const { - return Rect(mWidth, mHeight); - } - inline Rect bounds() const { return getBounds(); } - -private: - virtual void onVSyncReceived(int dpy, nsecs_t timestamp); - void init(uint32_t displayIndex) __attribute__((noinline)); - void fini() __attribute__((noinline)); - - sp<SurfaceFlinger> mFlinger; - EGLDisplay mDisplay; - EGLSurface mSurface; - EGLContext mContext; - EGLConfig mConfig; - float mDpiX; - float mDpiY; - float mRefreshRate; - float mDensity; - int mWidth; - int mHeight; - PixelFormat mFormat; - uint32_t mFlags; - mutable uint32_t mPageFlipCount; - GLint mMaxViewportDims[2]; - GLint mMaxTextureSize; - - nsecs_t mRefreshPeriod; - mutable nsecs_t mLastHwVSync; - - // constant once set - HWComposer* mHwc; - PowerHAL mPowerHAL; - - - mutable Mutex mLock; - - // protected by mLock - wp<VSyncHandler> mVSyncHandler; - - sp<FramebufferNativeWindow> mNativeWindow; -}; - -}; // namespace android - -#endif // ANDROID_DISPLAY_HARDWARE_H diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp deleted file mode 100644 index d3a8bde..0000000 --- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <errno.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> - -#include <unistd.h> -#include <fcntl.h> - -#include <utils/Log.h> - -#include "DisplayHardware/DisplayHardwareBase.h" -#include "SurfaceFlinger.h" - -// ---------------------------------------------------------------------------- -namespace android { - -static char const * const kSleepFileName = "/sys/power/wait_for_fb_sleep"; -static char const * const kWakeFileName = "/sys/power/wait_for_fb_wake"; - -// ---------------------------------------------------------------------------- - -DisplayHardwareBase::DisplayEventThread::DisplayEventThread( - const sp<SurfaceFlinger>& flinger) - : Thread(false), mFlinger(flinger) { -} - -DisplayHardwareBase::DisplayEventThread::~DisplayEventThread() { -} - -status_t DisplayHardwareBase::DisplayEventThread::initCheck() const { - return ((access(kSleepFileName, R_OK) == 0 && - access(kWakeFileName, R_OK) == 0)) ? NO_ERROR : NO_INIT; -} - -bool DisplayHardwareBase::DisplayEventThread::threadLoop() { - - if (waitForFbSleep() == NO_ERROR) { - sp<SurfaceFlinger> flinger = mFlinger.promote(); - ALOGD("About to give-up screen, flinger = %p", flinger.get()); - if (flinger != 0) { - flinger->screenReleased(); - } - if (waitForFbWake() == NO_ERROR) { - ALOGD("Screen about to return, flinger = %p", flinger.get()); - if (flinger != 0) { - flinger->screenAcquired(); - } - return true; - } - } - - // error, exit the thread - return false; -} - -status_t DisplayHardwareBase::DisplayEventThread::waitForFbSleep() { - int err = 0; - char buf; - int fd = open(kSleepFileName, O_RDONLY, 0); - // if the file doesn't exist, the error will be caught in read() below - do { - err = read(fd, &buf, 1); - } while (err < 0 && errno == EINTR); - close(fd); - ALOGE_IF(err<0, "*** ANDROID_WAIT_FOR_FB_SLEEP failed (%s)", strerror(errno)); - return err < 0 ? -errno : int(NO_ERROR); -} - -status_t DisplayHardwareBase::DisplayEventThread::waitForFbWake() { - int err = 0; - char buf; - int fd = open(kWakeFileName, O_RDONLY, 0); - // if the file doesn't exist, the error will be caught in read() below - do { - err = read(fd, &buf, 1); - } while (err < 0 && errno == EINTR); - close(fd); - ALOGE_IF(err<0, "*** ANDROID_WAIT_FOR_FB_WAKE failed (%s)", strerror(errno)); - return err < 0 ? -errno : int(NO_ERROR); -} - -// ---------------------------------------------------------------------------- - -DisplayHardwareBase::DisplayHardwareBase(const sp<SurfaceFlinger>& flinger, - uint32_t displayIndex) -{ - mScreenAcquired = true; - mDisplayEventThread = new DisplayEventThread(flinger); -} - -void DisplayHardwareBase::startSleepManagement() const { - if (mDisplayEventThread->initCheck() == NO_ERROR) { - mDisplayEventThread->run("DisplayEventThread", PRIORITY_URGENT_DISPLAY); - } else { - ALOGW("/sys/power/wait_for_fb_{wake|sleep} don't exist"); - } -} - -DisplayHardwareBase::~DisplayHardwareBase() { - // request exit - mDisplayEventThread->requestExitAndWait(); -} - -bool DisplayHardwareBase::canDraw() const { - return mScreenAcquired; -} - -void DisplayHardwareBase::releaseScreen() const { - mScreenAcquired = false; -} - -void DisplayHardwareBase::acquireScreen() const { - mScreenAcquired = true; -} - -bool DisplayHardwareBase::isScreenAcquired() const { - return mScreenAcquired; -} - -}; // namespace android diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h deleted file mode 100644 index 6857481..0000000 --- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_DISPLAY_HARDWARE_BASE_H -#define ANDROID_DISPLAY_HARDWARE_BASE_H - -#include <stdint.h> -#include <utils/RefBase.h> -#include <utils/StrongPointer.h> -#include <utils/threads.h> - -namespace android { - -class SurfaceFlinger; - -class DisplayHardwareBase -{ -public: - DisplayHardwareBase( - const sp<SurfaceFlinger>& flinger, - uint32_t displayIndex); - - ~DisplayHardwareBase(); - - void startSleepManagement() const; - - // console management - void releaseScreen() const; - void acquireScreen() const; - bool isScreenAcquired() const; - - bool canDraw() const; - - -private: - class DisplayEventThread : public Thread { - wp<SurfaceFlinger> mFlinger; - status_t waitForFbSleep(); - status_t waitForFbWake(); - public: - DisplayEventThread(const sp<SurfaceFlinger>& flinger); - virtual ~DisplayEventThread(); - virtual bool threadLoop(); - status_t initCheck() const; - }; - - sp<DisplayEventThread> mDisplayEventThread; - mutable int mScreenAcquired; -}; - -}; // namespace android - -#endif // ANDROID_DISPLAY_HARDWARE_BASE_H diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp new file mode 100644 index 0000000..6d33592 --- /dev/null +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp @@ -0,0 +1,203 @@ +/* + ** + ** Copyright 2012 The Android Open Source Project + ** + ** Licensed under the Apache License Version 2.0(the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing software + ** distributed under the License is distributed on an "AS IS" BASIS + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> + +#include <cutils/log.h> + +#include <utils/String8.h> + +#include <ui/Rect.h> + +#include <EGL/egl.h> + +#include <hardware/hardware.h> +#include <gui/SurfaceTextureClient.h> +#include <ui/GraphicBuffer.h> + +#include "DisplayHardware/FramebufferSurface.h" + +// ---------------------------------------------------------------------------- +namespace android { +// ---------------------------------------------------------------------------- + +sp<FramebufferSurface> FramebufferSurface::create() { + sp<FramebufferSurface> result = new FramebufferSurface(); + if (result->fbDev == NULL) { + result = NULL; + } + return result; +} + +// ---------------------------------------------------------------------------- + +class GraphicBufferAlloc : public BnGraphicBufferAlloc { +public: + GraphicBufferAlloc() { }; + virtual ~GraphicBufferAlloc() { }; + virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h, + PixelFormat format, uint32_t usage, status_t* error) { + sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage)); + return graphicBuffer; + } +}; + + +/* + * This implements the (main) framebuffer management. This class is used + * mostly by SurfaceFlinger, but also by command line GL application. + * + */ + +FramebufferSurface::FramebufferSurface(): + ConsumerBase(new BufferQueue(true, NUM_FRAME_BUFFERS, + new GraphicBufferAlloc())), + fbDev(0), + mCurrentBufferSlot(-1), + mCurrentBuffer(0) +{ + hw_module_t const* module; + + if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) { + int stride; + int err; + int i; + err = framebuffer_open(module, &fbDev); + ALOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err)); + + // bail out if we can't initialize the modules + if (!fbDev) + return; + + mName = "FramebufferSurface"; + mBufferQueue->setConsumerName(mName); + mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_FB | + GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER); + mBufferQueue->setDefaultBufferFormat(fbDev->format); + mBufferQueue->setDefaultBufferSize(fbDev->width, fbDev->height); + mBufferQueue->setSynchronousMode(true); + mBufferQueue->setBufferCountServer(NUM_FRAME_BUFFERS); + } else { + ALOGE("Couldn't get gralloc module"); + } +} + +status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>* buffer) { + Mutex::Autolock lock(mMutex); + + BufferQueue::BufferItem item; + status_t err = acquireBufferLocked(&item); + if (err == BufferQueue::NO_BUFFER_AVAILABLE) { + if (buffer != NULL) { + *buffer = mCurrentBuffer; + } + return NO_ERROR; + } else if (err != NO_ERROR) { + ALOGE("error acquiring buffer: %s (%d)", strerror(-err), err); + return err; + } + + // If the BufferQueue has freed and reallocated a buffer in mCurrentSlot + // then we may have acquired the slot we already own. If we had released + // our current buffer before we call acquireBuffer then that release call + // would have returned STALE_BUFFER_SLOT, and we would have called + // freeBufferLocked on that slot. Because the buffer slot has already + // been overwritten with the new buffer all we have to do is skip the + // releaseBuffer call and we should be in the same state we'd be in if we + // had released the old buffer first. + if (mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT && + item.mBuf != mCurrentBufferSlot) { + // Release the previous buffer. + err = releaseBufferLocked(mCurrentBufferSlot, EGL_NO_DISPLAY, + EGL_NO_SYNC_KHR, Fence::NO_FENCE); + if (err != NO_ERROR && err != BufferQueue::STALE_BUFFER_SLOT) { + ALOGE("error releasing buffer: %s (%d)", strerror(-err), err); + return err; + } + } + + mCurrentBufferSlot = item.mBuf; + mCurrentBuffer = mSlots[mCurrentBufferSlot].mGraphicBuffer; + if (item.mFence != NULL) { + item.mFence->wait(Fence::TIMEOUT_NEVER); + } + + if (buffer != NULL) { + *buffer = mCurrentBuffer; + } + + return NO_ERROR; +} + +FramebufferSurface::~FramebufferSurface() { + if (fbDev) { + framebuffer_close(fbDev); + } +} + +void FramebufferSurface::onFrameAvailable() { + // XXX: The following code is here temporarily as part of the transition + // away from the framebuffer HAL. + sp<GraphicBuffer> buf; + status_t err = nextBuffer(&buf); + if (err != NO_ERROR) { + ALOGE("error latching next FramebufferSurface buffer: %s (%d)", + strerror(-err), err); + return; + } + err = fbDev->post(fbDev, buf->handle); + if (err != NO_ERROR) { + ALOGE("error posting framebuffer: %d", err); + } +} + +void FramebufferSurface::freeBufferLocked(int slotIndex) { + ConsumerBase::freeBufferLocked(slotIndex); + if (slotIndex == mCurrentBufferSlot) { + mCurrentBufferSlot = BufferQueue::INVALID_BUFFER_SLOT; + } +} + +status_t FramebufferSurface::setUpdateRectangle(const Rect& r) +{ + return INVALID_OPERATION; +} + +status_t FramebufferSurface::compositionComplete() +{ + if (fbDev->compositionComplete) { + return fbDev->compositionComplete(fbDev); + } + return INVALID_OPERATION; +} + +void FramebufferSurface::dump(String8& result) { + if (fbDev->common.version >= 1 && fbDev->dump) { + const size_t SIZE = 4096; + char buffer[SIZE]; + fbDev->dump(fbDev, buffer, SIZE); + result.append(buffer); + } + ConsumerBase::dump(result); +} + +// ---------------------------------------------------------------------------- +}; // namespace android +// ---------------------------------------------------------------------------- diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h new file mode 100644 index 0000000..bfa500b --- /dev/null +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_SF_FRAMEBUFFER_SURFACE_H +#define ANDROID_SF_FRAMEBUFFER_SURFACE_H + +#include <stdint.h> +#include <sys/types.h> + +#include <gui/ConsumerBase.h> + +#define NUM_FRAME_BUFFERS 2 + +// --------------------------------------------------------------------------- +namespace android { +// --------------------------------------------------------------------------- + +class Rect; +class String8; + +// --------------------------------------------------------------------------- + +class FramebufferSurface : public ConsumerBase { +public: + + static sp<FramebufferSurface> create(); + + bool isUpdateOnDemand() const { return false; } + status_t setUpdateRectangle(const Rect& updateRect); + status_t compositionComplete(); + + virtual void dump(String8& result); + + // nextBuffer waits for and then latches the next buffer from the + // BufferQueue and releases the previously latched buffer to the + // BufferQueue. The new buffer is returned in the 'buffer' argument. + status_t nextBuffer(sp<GraphicBuffer>* buffer); + + // FIXME: currently there are information we can only get from the + // FB HAL, and FB HAL can only be instantiated once on some devices. + // Eventually this functionality will have to move in HWC or somewhere else. + const framebuffer_device_t* getFbHal() const { + return fbDev; + } + +private: + FramebufferSurface(); + virtual ~FramebufferSurface(); // this class cannot be overloaded + + virtual void onFrameAvailable(); + virtual void freeBufferLocked(int slotIndex); + + framebuffer_device_t* fbDev; + + // mCurrentBufferIndex is the slot index of the current buffer or + // INVALID_BUFFER_SLOT to indicate that either there is no current buffer + // or the buffer is not associated with a slot. + int mCurrentBufferSlot; + + // mCurrentBuffer is the current buffer or NULL to indicate that there is + // no current buffer. + sp<GraphicBuffer> mCurrentBuffer; +}; + +// --------------------------------------------------------------------------- +}; // namespace android +// --------------------------------------------------------------------------- + +#endif // ANDROID_SF_FRAMEBUFFER_SURFACE_H + diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 65763db..a3ec352 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -16,6 +16,9 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS +// Uncomment this to remove support for HWC_DEVICE_API_VERSION_0_3 and older +// #define HWC_REMOVE_DEPRECATED_VERSIONS 1 + #include <stdint.h> #include <stdio.h> #include <stdlib.h> @@ -28,63 +31,227 @@ #include <utils/Trace.h> #include <utils/Vector.h> +#include <ui/GraphicBuffer.h> + #include <hardware/hardware.h> #include <hardware/hwcomposer.h> #include <cutils/log.h> #include <cutils/properties.h> -#include <EGL/egl.h> - +#include "Layer.h" // needed only for debugging #include "LayerBase.h" #include "HWComposer.h" #include "SurfaceFlinger.h" namespace android { + +// --------------------------------------------------------------------------- +// Support for HWC_DEVICE_API_VERSION_0_3 and older: +// Since v0.3 is deprecated and support will be dropped soon, as much as +// possible the code is written to target v1.0. When using a v0.3 HWC, we +// allocate v0.3 structures, but assign them to v1.0 pointers. + +#if HWC_REMOVE_DEPRECATED_VERSIONS +// We need complete types to satisfy semantic checks, even though the code +// paths that use these won't get executed at runtime (and will likely be dead- +// code-eliminated). When we remove the code to support v0.3 we can remove +// these as well. +typedef hwc_layer_1_t hwc_layer_t; +typedef hwc_display_contents_1_t hwc_layer_list_t; +typedef hwc_composer_device_1_t hwc_composer_device_t; +#endif + +// This function assumes we've already rejected HWC's with lower-than-required +// versions. Don't use it for the initial "does HWC meet requirements" check! +static bool hwcHasVersion(const hwc_composer_device_1_t* hwc, uint32_t version) { + if (HWC_REMOVE_DEPRECATED_VERSIONS && + version <= HWC_DEVICE_API_VERSION_1_0) { + return true; + } else { + return hwc->common.version >= version; + } +} + +static bool hwcHasVsyncEvent(const hwc_composer_device_1_t* hwc) { + return hwcHasVersion(hwc, HWC_DEVICE_API_VERSION_0_3); +} + +static size_t sizeofHwcLayerList(const hwc_composer_device_1_t* hwc, + size_t numLayers) { + if (hwcHasVersion(hwc, HWC_DEVICE_API_VERSION_1_0)) { + return sizeof(hwc_display_contents_1_t) + numLayers*sizeof(hwc_layer_1_t); + } else { + return sizeof(hwc_layer_list_t) + numLayers*sizeof(hwc_layer_t); + } +} + +static int hwcEventControl(hwc_composer_device_1_t* hwc, int dpy, + int event, int enabled) { + if (hwcHasVersion(hwc, HWC_DEVICE_API_VERSION_1_0)) { + return hwc->methods->eventControl(hwc, dpy, event, enabled); + } else { + hwc_composer_device_t* hwc0 = reinterpret_cast<hwc_composer_device_t*>(hwc); + return hwc0->methods->eventControl(hwc0, event, enabled); + } +} + +static int hwcBlank(hwc_composer_device_1_t* hwc, int dpy, int blank) { + if (hwcHasVersion(hwc, HWC_DEVICE_API_VERSION_1_0)) { + return hwc->methods->blank(hwc, dpy, blank); + } else { + if (blank) { + hwc_composer_device_t* hwc0 = reinterpret_cast<hwc_composer_device_t*>(hwc); + return hwc0->set(hwc0, NULL, NULL, NULL); + } else { + // HWC 0.x turns the screen on at the next set() + return NO_ERROR; + } + } +} + +static int hwcPrepare(hwc_composer_device_1_t* hwc, + size_t numDisplays, hwc_display_contents_1_t** displays) { + if (hwcHasVersion(hwc, HWC_DEVICE_API_VERSION_1_0)) { + return hwc->prepare(hwc, numDisplays, displays); + } else { + hwc_composer_device_t* hwc0 = reinterpret_cast<hwc_composer_device_t*>(hwc); + hwc_layer_list_t* list0 = reinterpret_cast<hwc_layer_list_t*>(displays[0]); + // In the past, SurfaceFlinger would pass a NULL list when doing full + // OpenGL ES composition. I don't know what, if any, dependencies there + // are on this behavior, so I'm playing it safe and preserving it. + if (list0->numHwLayers == 0) + return hwc0->prepare(hwc0, NULL); + else + return hwc0->prepare(hwc0, list0); + } +} + +static int hwcSet(hwc_composer_device_1_t* hwc, EGLDisplay dpy, EGLSurface sur, + size_t numDisplays, hwc_display_contents_1_t** displays) { + int err; + if (hwcHasVersion(hwc, HWC_DEVICE_API_VERSION_1_0)) { + displays[0]->dpy = dpy; + displays[0]->sur = sur; + err = hwc->set(hwc, numDisplays, displays); + } else { + hwc_composer_device_t* hwc0 = reinterpret_cast<hwc_composer_device_t*>(hwc); + hwc_layer_list_t* list0 = reinterpret_cast<hwc_layer_list_t*>(displays[0]); + err = hwc0->set(hwc0, dpy, sur, list0); + } + return err; +} + +static uint32_t& hwcFlags(hwc_composer_device_1_t* hwc, + hwc_display_contents_1_t* display) { + if (hwcHasVersion(hwc, HWC_DEVICE_API_VERSION_1_0)) { + return display->flags; + } else { + hwc_layer_list_t* list0 = reinterpret_cast<hwc_layer_list_t*>(display); + return list0->flags; + } +} + +static size_t& hwcNumHwLayers(hwc_composer_device_1_t* hwc, + hwc_display_contents_1_t* display) { + if (hwcHasVersion(hwc, HWC_DEVICE_API_VERSION_1_0)) { + return display->numHwLayers; + } else { + hwc_layer_list_t* list0 = reinterpret_cast<hwc_layer_list_t*>(display); + return list0->numHwLayers; + } +} + +// --------------------------------------------------------------------------- + +struct HWComposer::cb_context { + struct callbacks : public hwc_procs_t { + // these are here to facilitate the transition when adding + // new callbacks (an implementation can check for NULL before + // calling a new callback). + void (*zero[4])(void); + }; + callbacks procs; + HWComposer* hwc; +}; + // --------------------------------------------------------------------------- HWComposer::HWComposer( const sp<SurfaceFlinger>& flinger, EventHandler& handler, - nsecs_t refreshPeriod) + framebuffer_device_t const* fbDev) : mFlinger(flinger), - mModule(0), mHwc(0), mList(0), mCapacity(0), + mModule(0), mHwc(0), mCapacity(0), mNumOVLayers(0), mNumFBLayers(0), - mDpy(EGL_NO_DISPLAY), mSur(EGL_NO_SURFACE), - mEventHandler(handler), - mRefreshPeriod(refreshPeriod), + mCBContext(new cb_context), + mEventHandler(handler), mRefreshPeriod(0), mVSyncCount(0), mDebugForceFakeVSync(false) { + for (size_t i = 0; i < MAX_DISPLAYS; i++) + mLists[i] = NULL; + char value[PROPERTY_VALUE_MAX]; property_get("debug.sf.no_hw_vsync", value, "0"); mDebugForceFakeVSync = atoi(value); - bool needVSyncThread = false; + bool needVSyncThread = true; int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule); ALOGW_IF(err, "%s module not found", HWC_HARDWARE_MODULE_ID); if (err == 0) { - err = hwc_open(mModule, &mHwc); + err = hwc_open_1(mModule, &mHwc); ALOGE_IF(err, "%s device failed to initialize (%s)", HWC_HARDWARE_COMPOSER, strerror(-err)); if (err == 0) { - if (mHwc->registerProcs) { - mCBContext.hwc = this; - mCBContext.procs.invalidate = &hook_invalidate; - mCBContext.procs.vsync = &hook_vsync; - mHwc->registerProcs(mHwc, &mCBContext.procs); - memset(mCBContext.procs.zero, 0, sizeof(mCBContext.procs.zero)); + if (HWC_REMOVE_DEPRECATED_VERSIONS && + mHwc->common.version < HWC_DEVICE_API_VERSION_1_0) { + ALOGE("%s device version %#x too old, will not be used", + HWC_HARDWARE_COMPOSER, mHwc->common.version); + hwc_close_1(mHwc); + mHwc = NULL; } - if (mHwc->common.version >= HWC_DEVICE_API_VERSION_0_3) { - if (mDebugForceFakeVSync) { - // make sure to turn h/w vsync off in "fake vsync" mode - mHwc->methods->eventControl(mHwc, HWC_EVENT_VSYNC, 0); + } + + if (mHwc) { + // always turn vsync off when we start + needVSyncThread = false; + if (hwcHasVsyncEvent(mHwc)) { + hwcEventControl(mHwc, 0, HWC_EVENT_VSYNC, 0); + + int period; + if (mHwc->query(mHwc, HWC_VSYNC_PERIOD, &period) == NO_ERROR) { + mRefreshPeriod = nsecs_t(period); } } else { needVSyncThread = true; } + + if (mHwc->registerProcs) { + mCBContext->hwc = this; + mCBContext->procs.invalidate = &hook_invalidate; + mCBContext->procs.vsync = &hook_vsync; + mHwc->registerProcs(mHwc, &mCBContext->procs); + memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero)); + } + + // create initial empty display contents for display 0 + createWorkList(MAIN, 0); } - } else { - needVSyncThread = true; + } + + + if (fbDev) { + if (mRefreshPeriod == 0) { + mRefreshPeriod = nsecs_t(1e9 / fbDev->fps); + ALOGW("getting VSYNC period from fb HAL: %lld", mRefreshPeriod); + } + mDpiX = fbDev->xdpi; + mDpiY = fbDev->ydpi; + } + + if (mRefreshPeriod == 0) { + mRefreshPeriod = nsecs_t(1e9 / 60.0); + ALOGW("getting VSYNC period thin air: %lld", mRefreshPeriod); } if (needVSyncThread) { @@ -94,14 +261,16 @@ HWComposer::HWComposer( } HWComposer::~HWComposer() { - eventControl(EVENT_VSYNC, 0); - free(mList); + hwcEventControl(mHwc, 0, EVENT_VSYNC, 0); + for (size_t i = 0; i < MAX_DISPLAYS; i++) + free(mLists[i]); if (mVSyncThread != NULL) { mVSyncThread->requestExitAndWait(); } if (mHwc) { - hwc_close(mHwc); + hwc_close_1(mHwc); } + delete mCBContext; } status_t HWComposer::initCheck() const { @@ -123,13 +292,36 @@ void HWComposer::invalidate() { void HWComposer::vsync(int dpy, int64_t timestamp) { ATRACE_INT("VSYNC", ++mVSyncCount&1); mEventHandler.onVSyncReceived(dpy, timestamp); + Mutex::Autolock _l(mLock); + mLastHwVSync = timestamp; +} + +nsecs_t HWComposer::getRefreshPeriod() const { + return mRefreshPeriod; +} + +nsecs_t HWComposer::getRefreshTimestamp() const { + // this returns the last refresh timestamp. + // if the last one is not available, we estimate it based on + // the refresh period and whatever closest timestamp we have. + Mutex::Autolock _l(mLock); + nsecs_t now = systemTime(CLOCK_MONOTONIC); + return now - ((now - mLastHwVSync) % mRefreshPeriod); +} + +float HWComposer::getDpiX() const { + return mDpiX; +} + +float HWComposer::getDpiY() const { + return mDpiY; } void HWComposer::eventControl(int event, int enabled) { status_t err = NO_ERROR; if (mHwc && mHwc->common.version >= HWC_DEVICE_API_VERSION_0_3) { if (!mDebugForceFakeVSync) { - err = mHwc->methods->eventControl(mHwc, event, enabled); + err = hwcEventControl(mHwc, 0, event, enabled); // error here should not happen -- not sure what we should // do if it does. ALOGE_IF(err, "eventControl(%d, %d) failed %s", @@ -142,37 +334,65 @@ void HWComposer::eventControl(int event, int enabled) { } } -void HWComposer::setFrameBuffer(EGLDisplay dpy, EGLSurface sur) { - mDpy = (hwc_display_t)dpy; - mSur = (hwc_surface_t)sur; -} +status_t HWComposer::createWorkList(int32_t id, size_t numLayers) { + // FIXME: handle multiple displays + if (uint32_t(id) >= MAX_DISPLAYS) + return BAD_INDEX; -status_t HWComposer::createWorkList(size_t numLayers) { if (mHwc) { - if (!mList || mCapacity < numLayers) { - free(mList); - size_t size = sizeof(hwc_layer_list) + numLayers*sizeof(hwc_layer_t); - mList = (hwc_layer_list_t*)malloc(size); + // TODO: must handle multiple displays here + // mLists[0] is NULL only when this is called from the constructor + if (!mLists[0] || mCapacity < numLayers) { + free(mLists[0]); + size_t size = sizeofHwcLayerList(mHwc, numLayers); + mLists[0] = (hwc_display_contents_1_t*)malloc(size); mCapacity = numLayers; } - mList->flags = HWC_GEOMETRY_CHANGED; - mList->numHwLayers = numLayers; + hwcFlags(mHwc, mLists[0]) = HWC_GEOMETRY_CHANGED; + hwcNumHwLayers(mHwc, mLists[0]) = numLayers; + if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) { + mLists[0]->flipFenceFd = -1; + } } return NO_ERROR; } status_t HWComposer::prepare() const { - int err = mHwc->prepare(mHwc, mList); + int err = hwcPrepare(mHwc, 1, + const_cast<hwc_display_contents_1_t**>(mLists)); if (err == NO_ERROR) { + + // here we're just making sure that "skip" layers are set + // to HWC_FRAMEBUFFER and we're also counting how many layers + // we have of each type. + // It would be nice if we could get rid of this entirely, which I + // think is almost possible. + + // TODO: must handle multiple displays here + size_t numOVLayers = 0; size_t numFBLayers = 0; - size_t count = mList->numHwLayers; + size_t count = getNumLayers(0); + for (size_t i=0 ; i<count ; i++) { - hwc_layer& l(mList->hwLayers[i]); - if (l.flags & HWC_SKIP_LAYER) { - l.compositionType = HWC_FRAMEBUFFER; + int compositionType; + if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) { + hwc_layer_1_t* l = &mLists[0]->hwLayers[i]; + if (l->flags & HWC_SKIP_LAYER) { + l->compositionType = HWC_FRAMEBUFFER; + } + compositionType = l->compositionType; + } else { + // mList really has hwc_layer_list_t memory layout + hwc_layer_list_t* list0 = reinterpret_cast<hwc_layer_list_t*>(mLists[0]); + hwc_layer_t* l = &list0->hwLayers[i]; + if (l->flags & HWC_SKIP_LAYER) { + l->compositionType = HWC_FRAMEBUFFER; + } + compositionType = l->compositionType; } - switch (l.compositionType) { + + switch (compositionType) { case HWC_OVERLAY: numOVLayers++; break; @@ -187,7 +407,15 @@ status_t HWComposer::prepare() const { return (status_t)err; } -size_t HWComposer::getLayerCount(int type) const { +size_t HWComposer::getLayerCount(int32_t id, int type) const { + // FIXME: handle multiple displays + if (uint32_t(id) >= MAX_DISPLAYS) { + // FIXME: in practice this is only use to know + // if we have at least one layer of type. + return (type == HWC_FRAMEBUFFER) ? 1 : 0; + } + + switch (type) { case HWC_OVERLAY: return mNumOVLayers; @@ -197,57 +425,274 @@ size_t HWComposer::getLayerCount(int type) const { return 0; } -status_t HWComposer::commit() const { - int err = mHwc->set(mHwc, mDpy, mSur, mList); - if (mList) { - mList->flags &= ~HWC_GEOMETRY_CHANGED; +status_t HWComposer::commit(void* fbDisplay, void* fbSurface) const { + int err = NO_ERROR; + if (mHwc) { + err = hwcSet(mHwc, fbDisplay, fbSurface, 1, + const_cast<hwc_display_contents_1_t**>(mLists)); + if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) { + if (mLists[0]->flipFenceFd != -1) { + close(mLists[0]->flipFenceFd); + mLists[0]->flipFenceFd = -1; + } + } + hwcFlags(mHwc, mLists[0]) &= ~HWC_GEOMETRY_CHANGED; } return (status_t)err; } status_t HWComposer::release() const { if (mHwc) { - if (mHwc->common.version >= HWC_DEVICE_API_VERSION_0_3) { - mHwc->methods->eventControl(mHwc, HWC_EVENT_VSYNC, 0); + if (hwcHasVsyncEvent(mHwc)) { + hwcEventControl(mHwc, 0, HWC_EVENT_VSYNC, 0); } - int err = mHwc->set(mHwc, NULL, NULL, NULL); - return (status_t)err; + return (status_t)hwcBlank(mHwc, 0, 1); + } + return NO_ERROR; +} + +status_t HWComposer::acquire() const { + if (mHwc) { + return (status_t)hwcBlank(mHwc, 0, 0); } return NO_ERROR; } status_t HWComposer::disable() { if (mHwc) { - free(mList); - mList = NULL; - int err = mHwc->prepare(mHwc, NULL); + hwcNumHwLayers(mHwc, mLists[0]) = 0; + int err = hwcPrepare(mHwc, 1, mLists); return (status_t)err; } return NO_ERROR; } -size_t HWComposer::getNumLayers() const { - return mList ? mList->numHwLayers : 0; +size_t HWComposer::getNumLayers(int32_t id) const { // FIXME: handle multiple displays + return mHwc ? hwcNumHwLayers(mHwc, mLists[0]) : 0; +} + +/* + * Helper template to implement a concrete HWCLayer + * This holds the pointer to the concrete hwc layer type + * and implements the "iterable" side of HWCLayer. + */ +template<typename CONCRETE, typename HWCTYPE> +class Iterable : public HWComposer::HWCLayer { +protected: + HWCTYPE* const mLayerList; + HWCTYPE* mCurrentLayer; + Iterable(HWCTYPE* layer) : mLayerList(layer), mCurrentLayer(layer) { } + inline HWCTYPE const * getLayer() const { return mCurrentLayer; } + inline HWCTYPE* getLayer() { return mCurrentLayer; } + virtual ~Iterable() { } +private: + // returns a copy of ourselves + virtual HWComposer::HWCLayer* dup() { + return new CONCRETE( static_cast<const CONCRETE&>(*this) ); + } + virtual status_t setLayer(size_t index) { + mCurrentLayer = &mLayerList[index]; + return NO_ERROR; + } +}; + +// #if !HWC_REMOVE_DEPRECATED_VERSIONS +/* + * Concrete implementation of HWCLayer for HWC_DEVICE_API_VERSION_0_3 + * This implements the HWCLayer side of HWCIterableLayer. + */ +class HWCLayerVersion0 : public Iterable<HWCLayerVersion0, hwc_layer_t> { +public: + HWCLayerVersion0(hwc_layer_t* layer) + : Iterable<HWCLayerVersion0, hwc_layer_t>(layer) { } + + virtual int32_t getCompositionType() const { + return getLayer()->compositionType; + } + virtual uint32_t getHints() const { + return getLayer()->hints; + } + virtual int getAndResetReleaseFenceFd() { + // not supported on VERSION_03 + return -1; + } + virtual void setAcquireFenceFd(int fenceFd) { + if (fenceFd != -1) { + ALOGE("HWC 0.x can't handle acquire fences"); + close(fenceFd); + } + } + + virtual void setDefaultState() { + getLayer()->compositionType = HWC_FRAMEBUFFER; + getLayer()->hints = 0; + getLayer()->flags = HWC_SKIP_LAYER; + getLayer()->transform = 0; + getLayer()->blending = HWC_BLENDING_NONE; + getLayer()->visibleRegionScreen.numRects = 0; + getLayer()->visibleRegionScreen.rects = NULL; + } + virtual void setSkip(bool skip) { + if (skip) { + getLayer()->flags |= HWC_SKIP_LAYER; + } else { + getLayer()->flags &= ~HWC_SKIP_LAYER; + } + } + virtual void setBlending(uint32_t blending) { + getLayer()->blending = blending; + } + virtual void setTransform(uint32_t transform) { + getLayer()->transform = transform; + } + virtual void setFrame(const Rect& frame) { + reinterpret_cast<Rect&>(getLayer()->displayFrame) = frame; + } + virtual void setCrop(const Rect& crop) { + reinterpret_cast<Rect&>(getLayer()->sourceCrop) = crop; + } + virtual void setVisibleRegionScreen(const Region& reg) { + getLayer()->visibleRegionScreen.rects = + reinterpret_cast<hwc_rect_t const *>( + reg.getArray(&getLayer()->visibleRegionScreen.numRects)); + } + virtual void setBuffer(const sp<GraphicBuffer>& buffer) { + if (buffer == 0 || buffer->handle == 0) { + getLayer()->compositionType = HWC_FRAMEBUFFER; + getLayer()->flags |= HWC_SKIP_LAYER; + getLayer()->handle = 0; + } else { + getLayer()->handle = buffer->handle; + } + } +}; +// #endif // !HWC_REMOVE_DEPRECATED_VERSIONS + +/* + * Concrete implementation of HWCLayer for HWC_DEVICE_API_VERSION_1_0. + * This implements the HWCLayer side of HWCIterableLayer. + */ +class HWCLayerVersion1 : public Iterable<HWCLayerVersion1, hwc_layer_1_t> { +public: + HWCLayerVersion1(hwc_layer_1_t* layer) + : Iterable<HWCLayerVersion1, hwc_layer_1_t>(layer) { } + + virtual int32_t getCompositionType() const { + return getLayer()->compositionType; + } + virtual uint32_t getHints() const { + return getLayer()->hints; + } + virtual int getAndResetReleaseFenceFd() { + int fd = getLayer()->releaseFenceFd; + getLayer()->releaseFenceFd = -1; + return fd; + } + virtual void setAcquireFenceFd(int fenceFd) { + getLayer()->acquireFenceFd = fenceFd; + } + + virtual void setDefaultState() { + getLayer()->compositionType = HWC_FRAMEBUFFER; + getLayer()->hints = 0; + getLayer()->flags = HWC_SKIP_LAYER; + getLayer()->transform = 0; + getLayer()->blending = HWC_BLENDING_NONE; + getLayer()->visibleRegionScreen.numRects = 0; + getLayer()->visibleRegionScreen.rects = NULL; + getLayer()->acquireFenceFd = -1; + getLayer()->releaseFenceFd = -1; + } + virtual void setSkip(bool skip) { + if (skip) { + getLayer()->flags |= HWC_SKIP_LAYER; + } else { + getLayer()->flags &= ~HWC_SKIP_LAYER; + } + } + virtual void setBlending(uint32_t blending) { + getLayer()->blending = blending; + } + virtual void setTransform(uint32_t transform) { + getLayer()->transform = transform; + } + virtual void setFrame(const Rect& frame) { + reinterpret_cast<Rect&>(getLayer()->displayFrame) = frame; + } + virtual void setCrop(const Rect& crop) { + reinterpret_cast<Rect&>(getLayer()->sourceCrop) = crop; + } + virtual void setVisibleRegionScreen(const Region& reg) { + getLayer()->visibleRegionScreen.rects = + reinterpret_cast<hwc_rect_t const *>( + reg.getArray(&getLayer()->visibleRegionScreen.numRects)); + } + virtual void setBuffer(const sp<GraphicBuffer>& buffer) { + if (buffer == 0 || buffer->handle == 0) { + getLayer()->compositionType = HWC_FRAMEBUFFER; + getLayer()->flags |= HWC_SKIP_LAYER; + getLayer()->handle = 0; + } else { + getLayer()->handle = buffer->handle; + } + } +}; + +/* + * returns an iterator initialized at a given index in the layer list + */ +HWComposer::LayerListIterator HWComposer::getLayerIterator(int32_t id, size_t index) { + // FIXME: handle multiple displays + if (uint32_t(id) >= MAX_DISPLAYS) + return LayerListIterator(); + + if (!mHwc || index > hwcNumHwLayers(mHwc, mLists[0])) + return LayerListIterator(); + if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) { + return LayerListIterator(new HWCLayerVersion1(mLists[0]->hwLayers), + index); + } else { + hwc_layer_list_t* list0 = reinterpret_cast<hwc_layer_list_t*>(mLists[0]); + return LayerListIterator(new HWCLayerVersion0(list0->hwLayers), index); + } +} + +/* + * returns an iterator on the beginning of the layer list + */ +HWComposer::LayerListIterator HWComposer::begin(int32_t id) { + return getLayerIterator(id, 0); } -hwc_layer_t* HWComposer::getLayers() const { - return mList ? mList->hwLayers : 0; +/* + * returns an iterator on the end of the layer list + */ +HWComposer::LayerListIterator HWComposer::end(int32_t id) { + return getLayerIterator(id, getNumLayers(id)); } void HWComposer::dump(String8& result, char* buffer, size_t SIZE, const Vector< sp<LayerBase> >& visibleLayersSortedByZ) const { - if (mHwc && mList) { + if (mHwc) { + hwc_layer_list_t* list0 = reinterpret_cast<hwc_layer_list_t*>(mLists[0]); + result.append("Hardware Composer state:\n"); result.appendFormat(" mDebugForceFakeVSync=%d\n", mDebugForceFakeVSync); result.appendFormat(" numHwLayers=%u, flags=%08x\n", - mList->numHwLayers, mList->flags); + hwcNumHwLayers(mHwc, mLists[0]), hwcFlags(mHwc, mLists[0])); result.append( " type | handle | hints | flags | tr | blend | format | source crop | frame name \n" "----------+----------+----------+----------+----+-------+----------+---------------------------+--------------------------------\n"); // " ________ | ________ | ________ | ________ | __ | _____ | ________ | [_____,_____,_____,_____] | [_____,_____,_____,_____] - for (size_t i=0 ; i<mList->numHwLayers ; i++) { - const hwc_layer_t& l(mList->hwLayers[i]); + for (size_t i=0 ; i<hwcNumHwLayers(mHwc, mLists[0]) ; i++) { + hwc_layer_1_t const* lp; + if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) { + lp = &mLists[0]->hwLayers[i]; + } else { + // FIXME: here we rely on hwc_layer_1_t and hwc_layer_t having the same layout + lp = reinterpret_cast<hwc_layer_1_t const*>(&list0->hwLayers[i]); + } const sp<LayerBase> layer(visibleLayersSortedByZ[i]); int32_t format = -1; if (layer->getLayer() != NULL) { @@ -256,6 +701,7 @@ void HWComposer::dump(String8& result, char* buffer, size_t SIZE, format = buffer->getPixelFormat(); } } + const hwc_layer_1_t& l(*lp); result.appendFormat( " %8s | %08x | %08x | %08x | %02x | %05x | %08x | [%5d,%5d,%5d,%5d] | [%5d,%5d,%5d,%5d] %s\n", l.compositionType ? "OVERLAY" : "FB", @@ -265,7 +711,7 @@ void HWComposer::dump(String8& result, char* buffer, size_t SIZE, layer->getName().string()); } } - if (mHwc && mHwc->common.version >= HWC_DEVICE_API_VERSION_0_1 && mHwc->dump) { + if (mHwc && hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_0_1) && mHwc->dump) { mHwc->dump(mHwc, buffer, SIZE); result.append(buffer); } diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index aada3cd..ac2257e 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -20,23 +20,32 @@ #include <stdint.h> #include <sys/types.h> -#include <EGL/egl.h> - -#include <hardware/hwcomposer.h> +#include <hardware/hwcomposer_defs.h> +#include <utils/Condition.h> +#include <utils/Mutex.h> #include <utils/StrongPointer.h> +#include <utils/Thread.h> +#include <utils/Timers.h> #include <utils/Vector.h> extern "C" int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *request, struct timespec *remain); +struct hwc_composer_device_1; +struct hwc_display_contents_1; +struct hwc_procs; +struct framebuffer_device_t; + namespace android { // --------------------------------------------------------------------------- +class GraphicBuffer; +class LayerBase; +class Region; class String8; class SurfaceFlinger; -class LayerBase; class HWComposer { @@ -48,17 +57,20 @@ public: virtual ~EventHandler() {} }; - HWComposer(const sp<SurfaceFlinger>& flinger, - EventHandler& handler, nsecs_t refreshPeriod); - ~HWComposer(); + enum { + MAIN = 0, + HDMI = 1, + MAX_DISPLAYS + }; - status_t initCheck() const; + HWComposer( + const sp<SurfaceFlinger>& flinger, + EventHandler& handler, + framebuffer_device_t const* fbDev); - // tells the HAL what the framebuffer is - void setFrameBuffer(EGLDisplay dpy, EGLSurface sur); + ~HWComposer(); - // create a work list for numLayers layer. sets HWC_GEOMETRY_CHANGED. - status_t createWorkList(size_t numLayers); + status_t initCheck() const; // Asks the HAL what it can do status_t prepare() const; @@ -67,18 +79,115 @@ public: status_t disable(); // commits the list - status_t commit() const; + status_t commit(void* fbDisplay, void* fbSurface) const; - // release hardware resources + // release hardware resources and blank screen status_t release() const; - // get the layer array created by createWorkList() - size_t getNumLayers() const; - hwc_layer_t* getLayers() const; + // acquire hardware resources and unblank screen + status_t acquire() const; + + // create a work list for numLayers layer. sets HWC_GEOMETRY_CHANGED. + status_t createWorkList(int32_t id, size_t numLayers); // get number of layers of the given type as updated in prepare(). // type is HWC_OVERLAY or HWC_FRAMEBUFFER - size_t getLayerCount(int type) const; + size_t getLayerCount(int32_t id, int type) const; + + // needed forward declarations + class LayerListIterator; + + /* + * Interface to hardware composer's layers functionality. + * This abstracts the HAL interface to layers which can evolve in + * incompatible ways from one release to another. + * The idea is that we could extend this interface as we add + * features to h/w composer. + */ + class HWCLayerInterface { + protected: + virtual ~HWCLayerInterface() { } + public: + virtual int32_t getCompositionType() const = 0; + virtual uint32_t getHints() const = 0; + virtual int getAndResetReleaseFenceFd() = 0; + virtual void setDefaultState() = 0; + virtual void setSkip(bool skip) = 0; + virtual void setBlending(uint32_t blending) = 0; + virtual void setTransform(uint32_t transform) = 0; + virtual void setFrame(const Rect& frame) = 0; + virtual void setCrop(const Rect& crop) = 0; + virtual void setVisibleRegionScreen(const Region& reg) = 0; + virtual void setBuffer(const sp<GraphicBuffer>& buffer) = 0; + virtual void setAcquireFenceFd(int fenceFd) = 0; + }; + + /* + * Interface used to implement an iterator to a list + * of HWCLayer. + */ + class HWCLayer : public HWCLayerInterface { + friend class LayerListIterator; + // select the layer at the given index + virtual status_t setLayer(size_t index) = 0; + virtual HWCLayer* dup() = 0; + static HWCLayer* copy(HWCLayer *rhs) { + return rhs ? rhs->dup() : NULL; + } + protected: + virtual ~HWCLayer() { } + }; + + /* + * Iterator through a HWCLayer list. + * This behaves more or less like a forward iterator. + */ + class LayerListIterator { + friend struct HWComposer; + HWCLayer* const mLayerList; + size_t mIndex; + + LayerListIterator() : mLayerList(NULL), mIndex(0) { } + + LayerListIterator(HWCLayer* layer, size_t index) + : mLayerList(layer), mIndex(index) { } + + // we don't allow assignment, because we don't need it for now + LayerListIterator& operator = (const LayerListIterator& rhs); + + public: + // copy operators + LayerListIterator(const LayerListIterator& rhs) + : mLayerList(HWCLayer::copy(rhs.mLayerList)), mIndex(rhs.mIndex) { + } + + ~LayerListIterator() { delete mLayerList; } + + // pre-increment + LayerListIterator& operator++() { + mLayerList->setLayer(++mIndex); + return *this; + } + + // dereference + HWCLayerInterface& operator * () { return *mLayerList; } + HWCLayerInterface* operator -> () { return mLayerList; } + + // comparison + bool operator == (const LayerListIterator& rhs) const { + return mIndex == rhs.mIndex; + } + bool operator != (const LayerListIterator& rhs) const { + return !operator==(rhs); + } + }; + + // Returns an iterator to the beginning of the layer list + LayerListIterator begin(int32_t id); + + // Returns an iterator to the end of the layer list + LayerListIterator end(int32_t id); + // Events handling --------------------------------------------------------- @@ -88,6 +197,11 @@ public: void eventControl(int event, int enabled); + nsecs_t getRefreshPeriod() const; + nsecs_t getRefreshTimestamp() const; + float getDpiX() const; + float getDpiY() const; + // this class is only used to fake the VSync event on systems that don't // have it. class VSyncThread : public Thread { @@ -112,17 +226,10 @@ public: private: - struct callbacks : public hwc_procs_t { - // these are here to facilitate the transition when adding - // new callbacks (an implementation can check for NULL before - // calling a new callback). - void (*zero[4])(void); - }; + LayerListIterator getLayerIterator(int32_t id, size_t index); + size_t getNumLayers(int32_t id) const; - struct cb_context { - callbacks procs; - HWComposer* hwc; - }; + struct cb_context; static void hook_invalidate(struct hwc_procs* procs); static void hook_vsync(struct hwc_procs* procs, int dpy, int64_t timestamp); @@ -130,23 +237,31 @@ private: inline void invalidate(); inline void vsync(int dpy, int64_t timestamp); - sp<SurfaceFlinger> mFlinger; - hw_module_t const* mModule; - hwc_composer_device_t* mHwc; - hwc_layer_list_t* mList; - size_t mCapacity; - mutable size_t mNumOVLayers; - mutable size_t mNumFBLayers; - hwc_display_t mDpy; - hwc_surface_t mSur; - cb_context mCBContext; - EventHandler& mEventHandler; - nsecs_t mRefreshPeriod; - size_t mVSyncCount; - sp<VSyncThread> mVSyncThread; - bool mDebugForceFakeVSync; -}; + sp<SurfaceFlinger> mFlinger; + hw_module_t const* mModule; + struct hwc_composer_device_1* mHwc; + // invariant: mLists[0] != NULL iff mHwc != NULL + // TODO: decide whether mLists[i>0] should be non-NULL when display i is + // not attached/enabled. + struct hwc_display_contents_1* mLists[MAX_DISPLAYS]; + + size_t mCapacity; + mutable size_t mNumOVLayers; + mutable size_t mNumFBLayers; + cb_context* mCBContext; + EventHandler& mEventHandler; + nsecs_t mRefreshPeriod; + float mDpiX; + float mDpiY; + size_t mVSyncCount; + sp<VSyncThread> mVSyncThread; + bool mDebugForceFakeVSync; + + // protected by mLock + mutable Mutex mLock; + mutable nsecs_t mLastHwVSync; +}; // --------------------------------------------------------------------------- }; // namespace android diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp index 7c1aebe..9b61fa9 100644 --- a/services/surfaceflinger/EventThread.cpp +++ b/services/surfaceflinger/EventThread.cpp @@ -24,31 +24,26 @@ #include <gui/DisplayEventReceiver.h> #include <utils/Errors.h> +#include <utils/String8.h> #include <utils/Trace.h> -#include "DisplayHardware/DisplayHardware.h" #include "EventThread.h" #include "SurfaceFlinger.h" // --------------------------------------------------------------------------- - namespace android { - // --------------------------------------------------------------------------- EventThread::EventThread(const sp<SurfaceFlinger>& flinger) : mFlinger(flinger), - mHw(flinger->graphicPlane(0).editDisplayHardware()), mLastVSyncTimestamp(0), mVSyncTimestamp(0), mUseSoftwareVSync(false), mDeliveredEvents(0), - mDebugVsyncEnabled(false) -{ + mDebugVsyncEnabled(false) { } void EventThread::onFirstRef() { - mHw.setVSyncHandler(this); run("EventThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE); } @@ -254,13 +249,15 @@ bool EventThread::threadLoop() { void EventThread::enableVSyncLocked() { if (!mUseSoftwareVSync) { // never enable h/w VSYNC when screen is off - mHw.eventControl(DisplayHardware::EVENT_VSYNC, true); + mFlinger->eventControl(SurfaceFlinger::EVENT_VSYNC, true); + mPowerHAL.vsyncHint(true); } mDebugVsyncEnabled = true; } void EventThread::disableVSyncLocked() { - mHw.eventControl(DisplayHardware::EVENT_VSYNC, false); + mFlinger->eventControl(SurfaceFlinger::EVENT_VSYNC, false); + mPowerHAL.vsyncHint(false); mDebugVsyncEnabled = false; } diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h index b42cab6..a71d985 100644 --- a/services/surfaceflinger/EventThread.h +++ b/services/surfaceflinger/EventThread.h @@ -27,19 +27,18 @@ #include <utils/threads.h> #include <utils/SortedVector.h> -#include "DisplayHardware/DisplayHardware.h" +#include "DisplayHardware/PowerHAL.h" // --------------------------------------------------------------------------- - namespace android { - // --------------------------------------------------------------------------- class SurfaceFlinger; +class String8; // --------------------------------------------------------------------------- -class EventThread : public Thread, public DisplayHardware::VSyncHandler { +class EventThread : public Thread { class Connection : public BnDisplayEventConnection { public: Connection(const sp<EventThread>& eventThread); @@ -78,13 +77,15 @@ public: // called after the screen is turned on from main thread void onScreenAcquired(); + // called when receiving a vsync event + void onVSyncReceived(int display, nsecs_t timestamp); + void dump(String8& result, char* buffer, size_t SIZE) const; private: virtual bool threadLoop(); virtual status_t readyToRun(); virtual void onFirstRef(); - virtual void onVSyncReceived(int, nsecs_t timestamp); void removeDisplayEventConnection(const wp<Connection>& connection); void enableVSyncLocked(); @@ -92,7 +93,7 @@ private: // constants sp<SurfaceFlinger> mFlinger; - DisplayHardware& mHw; + PowerHAL mPowerHAL; mutable Mutex mLock; mutable Condition mCondition; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 4062340..0825ec6 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -36,13 +36,14 @@ #include <gui/Surface.h> #include "clz.h" -#include "DisplayHardware/DisplayHardware.h" -#include "DisplayHardware/HWComposer.h" +#include "DisplayDevice.h" #include "GLExtensions.h" #include "Layer.h" #include "SurfaceFlinger.h" #include "SurfaceTextureLayer.h" +#include "DisplayHardware/HWComposer.h" + #define DEBUG_RESIZE 0 namespace android { @@ -63,7 +64,6 @@ Layer::Layer(SurfaceFlinger* flinger, mFormat(PIXEL_FORMAT_NONE), mGLExtensions(GLExtensions::getInstance()), mOpaqueLayer(true), - mNeedsDithering(false), mSecure(false), mProtectedByApp(false) { @@ -71,14 +71,10 @@ Layer::Layer(SurfaceFlinger* flinger, glGenTextures(1, &mTextureName); } -void Layer::onLayerDisplayed() { - if (mFrameLatencyNeeded) { - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - mFrameStats[mFrameLatencyOffset].timestamp = mSurfaceTexture->getTimestamp(); - mFrameStats[mFrameLatencyOffset].set = systemTime(); - mFrameStats[mFrameLatencyOffset].vsync = hw.getRefreshTimestamp(); - mFrameLatencyOffset = (mFrameLatencyOffset + 1) % 128; - mFrameLatencyNeeded = false; +void Layer::onLayerDisplayed(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface* layer) { + if (layer) { + mSurfaceTexture->setReleaseFence(layer->getAndResetReleaseFenceFd()); } } @@ -117,8 +113,7 @@ void Layer::onFirstRef() Layer::~Layer() { - mFlinger->postMessageAsync( - new SurfaceFlinger::MessageDestroyGLTexture(mTextureName) ); + mFlinger->deleteTextureAsync(mTextureName); } void Layer::onFrameQueued() { @@ -138,14 +133,6 @@ void Layer::setName(const String8& name) { mSurfaceTexture->setName(name); } -void Layer::validateVisibility(const Transform& globalTransform) { - LayerBase::validateVisibility(globalTransform); - - // This optimization allows the SurfaceTexture to bake in - // the rotation so hardware overlays can be used - mSurfaceTexture->setTransformHint(getTransformHint()); -} - sp<ISurface> Layer::createSurface() { class BSurface : public BnSurface, public LayerCleaner { @@ -183,10 +170,8 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h, return err; } - // the display's pixel format - const DisplayHardware& hw(graphicPlane(0).displayHardware()); uint32_t const maxSurfaceDims = min( - hw.getMaxTextureSize(), hw.getMaxViewportDims()); + mFlinger->getMaxTextureSize(), mFlinger->getMaxViewportDims()); // never allow a surface larger than what our underlying GL implementation // can handle. @@ -195,26 +180,17 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h, return BAD_VALUE; } - PixelFormatInfo displayInfo; - getPixelFormatInfo(hw.getFormat(), &displayInfo); - const uint32_t hwFlags = hw.getFlags(); - mFormat = format; - mSecure = (flags & ISurfaceComposer::eSecure) ? true : false; - mProtectedByApp = (flags & ISurfaceComposer::eProtectedByApp) ? true : false; - mOpaqueLayer = (flags & ISurfaceComposer::eOpaque); + mSecure = (flags & ISurfaceComposerClient::eSecure) ? true : false; + mProtectedByApp = (flags & ISurfaceComposerClient::eProtectedByApp) ? true : false; + mOpaqueLayer = (flags & ISurfaceComposerClient::eOpaque); mCurrentOpacity = getOpacityForFormat(format); mSurfaceTexture->setDefaultBufferSize(w, h); mSurfaceTexture->setDefaultBufferFormat(format); mSurfaceTexture->setConsumerUsageBits(getEffectiveUsage(0)); - // we use the red index - int displayRedSize = displayInfo.getSize(PixelFormatInfo::INDEX_RED); - int layerRedsize = info.getSize(PixelFormatInfo::INDEX_RED); - mNeedsDithering = layerRedsize > displayRedSize; - return NO_ERROR; } @@ -226,7 +202,8 @@ Rect Layer::computeBufferCrop() const { } else if (mActiveBuffer != NULL){ crop = Rect(mActiveBuffer->getWidth(), mActiveBuffer->getHeight()); } else { - crop = Rect(mTransformedBounds.width(), mTransformedBounds.height()); + crop.makeInvalid(); + return crop; } // ... then reduce that in the same proportions as the window crop reduces @@ -259,16 +236,19 @@ Rect Layer::computeBufferCrop() const { return crop; } -void Layer::setGeometry(hwc_layer_t* hwcl) +void Layer::setGeometry( + const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer) { - LayerBaseClient::setGeometry(hwcl); + LayerBaseClient::setGeometry(hw, layer); - hwcl->flags &= ~HWC_SKIP_LAYER; + // enable this layer + layer.setSkip(false); // we can't do alpha-fade with the hwc HAL const State& s(drawingState()); if (s.alpha < 0xFF) { - hwcl->flags = HWC_SKIP_LAYER; + layer.setSkip(true); } /* @@ -276,44 +256,52 @@ void Layer::setGeometry(hwc_layer_t* hwcl) * 1) buffer orientation/flip/mirror * 2) state transformation (window manager) * 3) layer orientation (screen orientation) - * mTransform is already the composition of (2) and (3) * (NOTE: the matrices are multiplied in reverse order) */ const Transform bufferOrientation(mCurrentTransform); - const Transform tr(mTransform * bufferOrientation); + const Transform tr(hw->getTransform() * s.transform * bufferOrientation); // this gives us only the "orientation" component of the transform const uint32_t finalTransform = tr.getOrientation(); // we can only handle simple transformation if (finalTransform & Transform::ROT_INVALID) { - hwcl->flags = HWC_SKIP_LAYER; + layer.setSkip(true); } else { - hwcl->transform = finalTransform; + layer.setTransform(finalTransform); } - - Rect crop = computeBufferCrop(); - hwcl->sourceCrop.left = crop.left; - hwcl->sourceCrop.top = crop.top; - hwcl->sourceCrop.right = crop.right; - hwcl->sourceCrop.bottom = crop.bottom; + layer.setCrop(computeBufferCrop()); } -void Layer::setPerFrameData(hwc_layer_t* hwcl) { +void Layer::setPerFrameData(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer) { const sp<GraphicBuffer>& buffer(mActiveBuffer); - if (buffer == NULL) { - // this can happen if the client never drew into this layer yet, - // or if we ran out of memory. In that case, don't let - // HWC handle it. - hwcl->flags |= HWC_SKIP_LAYER; - hwcl->handle = NULL; - } else { - hwcl->handle = buffer->handle; + // NOTE: buffer can be NULL if the client never drew into this + // layer yet, or if we ran out of memory + layer.setBuffer(buffer); +} + +void Layer::setAcquireFence(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer) { + int fenceFd = -1; + + // TODO: there is a possible optimization here: we only need to set the + // acquire fence the first time a new buffer is acquired on EACH display. + + if (layer.getCompositionType() == HWC_OVERLAY) { + sp<Fence> fence = mSurfaceTexture->getCurrentFence(); + if (fence.get()) { + fenceFd = fence->dup(); + if (fenceFd == -1) { + ALOGW("failed to dup layer fence, skipping sync: %d", errno); + } + } } + layer.setAcquireFenceFd(fenceFd); } -void Layer::onDraw(const Region& clip) const +void Layer::onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const { ATRACE_CALL(); @@ -335,16 +323,25 @@ void Layer::onDraw(const Region& clip) const const sp<LayerBase>& layer(drawingLayers[i]); if (layer.get() == static_cast<LayerBase const*>(this)) break; - under.orSelf(layer->visibleRegionScreen); + under.orSelf( hw->getTransform().transform(layer->visibleRegion) ); } // if not everything below us is covered, we plug the holes! Region holes(clip.subtract(under)); if (!holes.isEmpty()) { - clearWithOpenGL(holes, 0, 0, 0, 1); + clearWithOpenGL(hw, holes, 0, 0, 0, 1); } return; } + // TODO: replace this with a server-side wait + sp<Fence> fence = mSurfaceTexture->getCurrentFence(); + if (fence.get()) { + status_t err = fence->wait(Fence::TIMEOUT_NEVER); + ALOGW_IF(err != OK, "Layer::onDraw: failed waiting for fence: %d", err); + // Go ahead and draw the buffer anyway; no matter what we do the screen + // is probably going to have something visibly wrong. + } + if (!isProtected()) { // TODO: we could be more subtle with isFixedSize() const bool useFiltering = getFiltering() || needsFiltering() || isFixedSize(); @@ -376,7 +373,7 @@ void Layer::onDraw(const Region& clip) const glEnable(GL_TEXTURE_2D); } - drawWithOpenGL(clip); + drawWithOpenGL(hw, clip); glDisable(GL_TEXTURE_EXTERNAL_OES); glDisable(GL_TEXTURE_2D); @@ -514,10 +511,23 @@ bool Layer::onPreComposition() { return mQueuedFrames > 0; } -void Layer::lockPageFlip(bool& recomputeVisibleRegions) +void Layer::onPostComposition() { + if (mFrameLatencyNeeded) { + const HWComposer& hwc = mFlinger->getHwComposer(); + const size_t offset = mFrameLatencyOffset; + mFrameStats[offset].timestamp = mSurfaceTexture->getTimestamp(); + mFrameStats[offset].set = systemTime(); + mFrameStats[offset].vsync = hwc.getRefreshTimestamp(); + mFrameLatencyOffset = (mFrameLatencyOffset + 1) % 128; + mFrameLatencyNeeded = false; + } +} + +Region Layer::latchBuffer(bool& recomputeVisibleRegions) { ATRACE_CALL(); + Region outDirtyRegion; if (mQueuedFrames > 0) { // if we've already called updateTexImage() without going through @@ -526,8 +536,7 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) // compositionComplete() call. // we'll trigger an update in onPreComposition(). if (mRefreshPending) { - mPostedDirtyRegion.clear(); - return; + return outDirtyRegion; } // Capture the old state of the layer for comparisons later @@ -624,17 +633,21 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) Reject r(mDrawingState, currentState(), recomputeVisibleRegions); + // XXX: not sure if setTransformHint belongs here + // it should only be needed when the main screen orientation changes + mSurfaceTexture->setTransformHint(getTransformHint()); + if (mSurfaceTexture->updateTexImage(&r) < NO_ERROR) { // something happened! recomputeVisibleRegions = true; - return; + return outDirtyRegion; } // update the active buffer mActiveBuffer = mSurfaceTexture->getCurrentBuffer(); if (mActiveBuffer == NULL) { // this can only happen if the very first buffer was rejected. - return; + return outDirtyRegion; } mRefreshPending = true; @@ -672,38 +685,17 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) recomputeVisibleRegions = true; } - // FIXME: mPostedDirtyRegion = dirty & bounds - const Layer::State& front(drawingState()); - mPostedDirtyRegion.set(front.active.w, front.active.h); - glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } -} -void Layer::unlockPageFlip( - const Transform& planeTransform, Region& outDirtyRegion) -{ - ATRACE_CALL(); + // FIXME: postedRegion should be dirty & bounds + const Layer::State& front(drawingState()); + Region dirtyRegion(Rect(front.active.w, front.active.h)); - Region postedRegion(mPostedDirtyRegion); - if (!postedRegion.isEmpty()) { - mPostedDirtyRegion.clear(); - if (!visibleRegionScreen.isEmpty()) { - // The dirty region is given in the layer's coordinate space - // transform the dirty region by the surface's transformation - // and the global transformation. - const Layer::State& s(drawingState()); - const Transform tr(planeTransform * s.transform); - postedRegion = tr.transform(postedRegion); - - // At this point, the dirty region is in screen space. - // Make sure it's constrained by the visible region (which - // is in screen space as well). - postedRegion.andSelf(visibleRegionScreen); - outDirtyRegion.orSelf(postedRegion); - } + // transform the dirty region to window-manager space + outDirtyRegion = (front.transform.transform(dirtyRegion)); } + return outDirtyRegion; } void Layer::dump(String8& result, char* buffer, size_t SIZE) const @@ -736,8 +728,7 @@ void Layer::dumpStats(String8& result, char* buffer, size_t SIZE) const { LayerBaseClient::dumpStats(result, buffer, SIZE); const size_t o = mFrameLatencyOffset; - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - const nsecs_t period = hw.getRefreshPeriod(); + const nsecs_t period = mFlinger->getHwComposer().getRefreshPeriod(); result.appendFormat("%lld\n", period); for (size_t i=0 ; i<128 ; i++) { const size_t index = (o+i) % 128; @@ -772,7 +763,14 @@ uint32_t Layer::getEffectiveUsage(uint32_t usage) const uint32_t Layer::getTransformHint() const { uint32_t orientation = 0; if (!mFlinger->mDebugDisableTransformHint) { - orientation = getPlaneOrientation(); + // The transform hint is used to improve performance on the main + // display -- we can only have a single transform hint, it cannot + // apply to all displays. + // This is why we use the default display here. This is not an + // oversight. + sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice()); + const Transform& planeTransform(hw->getTransform()); + orientation = planeTransform.getOrientation(); if (orientation & Transform::ROT_INVALID) { orientation = 0; } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 393599f..d24013b 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -64,27 +64,30 @@ public: bool isFixedSize() const; // LayerBase interface - virtual void setGeometry(hwc_layer_t* hwcl); - virtual void setPerFrameData(hwc_layer_t* hwcl); - virtual void onDraw(const Region& clip) const; + virtual void setGeometry(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer); + virtual void setPerFrameData(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer); + virtual void setAcquireFence(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer); + virtual void onLayerDisplayed(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface* layer); + virtual bool onPreComposition(); + virtual void onPostComposition(); + + virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const; virtual uint32_t doTransaction(uint32_t transactionFlags); - virtual void lockPageFlip(bool& recomputeVisibleRegions); - virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion); + virtual Region latchBuffer(bool& recomputeVisibleRegions); virtual bool isOpaque() const; - virtual bool needsDithering() const { return mNeedsDithering; } virtual bool isSecure() const { return mSecure; } virtual bool isProtected() const; virtual void onRemoved(); virtual sp<Layer> getLayer() const { return const_cast<Layer*>(this); } virtual void setName(const String8& name); - virtual void validateVisibility(const Transform& globalTransform); // LayerBaseClient interface virtual wp<IBinder> getSurfaceTextureBinder() const; - virtual void onLayerDisplayed(); - virtual bool onPreComposition(); - // only for debugging inline const sp<GraphicBuffer>& getActiveBuffer() const { return mActiveBuffer; } @@ -137,12 +140,10 @@ private: PixelFormat mFormat; const GLExtensions& mGLExtensions; bool mOpaqueLayer; - bool mNeedsDithering; // page-flip thread (currently main thread) bool mSecure; // no screenshots bool mProtectedByApp; // application requires protected path to external sink - Region mPostedDirtyRegion; }; // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp index 16bac8f..2311e6d 100644 --- a/services/surfaceflinger/LayerBase.cpp +++ b/services/surfaceflinger/LayerBase.cpp @@ -29,9 +29,11 @@ #include <hardware/hardware.h> #include "clz.h" +#include "Client.h" #include "LayerBase.h" +#include "Layer.h" #include "SurfaceFlinger.h" -#include "DisplayHardware/DisplayHardware.h" +#include "DisplayDevice.h" namespace android { @@ -44,13 +46,9 @@ LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display) sequence(uint32_t(android_atomic_inc(&sSequence))), mFlinger(flinger), mFiltering(false), mNeedsFiltering(false), - mOrientation(0), - mPlaneOrientation(0), mTransactionFlags(0), mPremultipliedAlpha(true), mName("unnamed"), mDebug(false) { - const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware()); - mFlags = hw.getFlags(); } LayerBase::~LayerBase() @@ -65,23 +63,13 @@ String8 LayerBase::getName() const { return mName; } -const GraphicPlane& LayerBase::graphicPlane(int dpy) const -{ - return mFlinger->graphicPlane(dpy); -} - -GraphicPlane& LayerBase::graphicPlane(int dpy) -{ - return mFlinger->graphicPlane(dpy); -} - void LayerBase::initStates(uint32_t w, uint32_t h, uint32_t flags) { uint32_t layerFlags = 0; - if (flags & ISurfaceComposer::eHidden) - layerFlags = ISurfaceComposer::eLayerHidden; + if (flags & ISurfaceComposerClient::eHidden) + layerFlags = layer_state_t::eLayerHidden; - if (flags & ISurfaceComposer::eNonPremultiplied) + if (flags & ISurfaceComposerClient::eNonPremultiplied) mPremultipliedAlpha = false; mCurrentState.active.w = w; @@ -89,6 +77,7 @@ void LayerBase::initStates(uint32_t w, uint32_t h, uint32_t flags) mCurrentState.active.crop.makeInvalid(); mCurrentState.z = 0; mCurrentState.alpha = 0xFF; + mCurrentState.layerStack = 0; mCurrentState.flags = layerFlags; mCurrentState.sequence = 0; mCurrentState.transform.set(0, 0); @@ -181,19 +170,23 @@ bool LayerBase::setCrop(const Rect& crop) { return true; } -Rect LayerBase::visibleBounds() const -{ - return mTransformedBounds; -} +bool LayerBase::setLayerStack(uint32_t layerStack) { + if (mCurrentState.layerStack == layerStack) + return false; + mCurrentState.sequence++; + mCurrentState.layerStack = layerStack; + requestTransaction(); + return true; +} void LayerBase::setVisibleRegion(const Region& visibleRegion) { // always called from main thread - visibleRegionScreen = visibleRegion; + this->visibleRegion = visibleRegion; } void LayerBase::setCoveredRegion(const Region& coveredRegion) { // always called from main thread - coveredRegionScreen = coveredRegion; + this->coveredRegion = coveredRegion; } uint32_t LayerBase::doTransaction(uint32_t flags) @@ -230,99 +223,82 @@ uint32_t LayerBase::doTransaction(uint32_t flags) return flags; } -void LayerBase::validateVisibility(const Transform& planeTransform) +void LayerBase::computeGeometry(const sp<const DisplayDevice>& hw, LayerMesh* mesh) const { const Layer::State& s(drawingState()); - const Transform tr(planeTransform * s.transform); - const bool transformed = tr.transformed(); - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - const uint32_t hw_h = hw.getHeight(); + const Transform tr(hw->getTransform() * s.transform); + const uint32_t hw_h = hw->getHeight(); const Rect& crop(s.active.crop); - Rect win(s.active.w, s.active.h); if (!crop.isEmpty()) { win.intersect(crop, &win); } - - mNumVertices = 4; - tr.transform(mVertices[0], win.left, win.top); - tr.transform(mVertices[1], win.left, win.bottom); - tr.transform(mVertices[2], win.right, win.bottom); - tr.transform(mVertices[3], win.right, win.top); - for (size_t i=0 ; i<4 ; i++) - mVertices[i][1] = hw_h - mVertices[i][1]; - - if (CC_UNLIKELY(transformed)) { - // NOTE: here we could also punt if we have too many rectangles - // in the transparent region - if (tr.preserveRects()) { - // transform the transparent region - transparentRegionScreen = tr.transform(s.transparentRegion); - } else { - // transformation too complex, can't do the transparent region - // optimization. - transparentRegionScreen.clear(); + if (mesh) { + tr.transform(mesh->mVertices[0], win.left, win.top); + tr.transform(mesh->mVertices[1], win.left, win.bottom); + tr.transform(mesh->mVertices[2], win.right, win.bottom); + tr.transform(mesh->mVertices[3], win.right, win.top); + for (size_t i=0 ; i<4 ; i++) { + mesh->mVertices[i][1] = hw_h - mesh->mVertices[i][1]; } - } else { - transparentRegionScreen = s.transparentRegion; } - - // cache a few things... - mOrientation = tr.getOrientation(); - mPlaneOrientation = planeTransform.getOrientation(); - mTransform = tr; - mTransformedBounds = tr.transform(win); } -void LayerBase::lockPageFlip(bool& recomputeVisibleRegions) { +Rect LayerBase::computeBounds() const { + const Layer::State& s(drawingState()); + const Rect& crop(s.active.crop); + Rect win(s.active.w, s.active.h); + if (!crop.isEmpty()) { + win.intersect(crop, &win); + } + return s.transform.transform(win); } -void LayerBase::unlockPageFlip( - const Transform& planeTransform, Region& outDirtyRegion) { +Region LayerBase::latchBuffer(bool& recomputeVisibleRegions) { + Region result; + return result; } -void LayerBase::setGeometry(hwc_layer_t* hwcl) +void LayerBase::setGeometry( + const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer) { - hwcl->compositionType = HWC_FRAMEBUFFER; - hwcl->hints = 0; - hwcl->flags = HWC_SKIP_LAYER; - hwcl->transform = 0; - hwcl->blending = HWC_BLENDING_NONE; + layer.setDefaultState(); // this gives us only the "orientation" component of the transform const State& s(drawingState()); const uint32_t finalTransform = s.transform.getOrientation(); // we can only handle simple transformation if (finalTransform & Transform::ROT_INVALID) { - hwcl->flags = HWC_SKIP_LAYER; + layer.setTransform(0); } else { - hwcl->transform = finalTransform; + layer.setTransform(finalTransform); } if (!isOpaque()) { - hwcl->blending = mPremultipliedAlpha ? - HWC_BLENDING_PREMULT : HWC_BLENDING_COVERAGE; + layer.setBlending(mPremultipliedAlpha ? + HWC_BLENDING_PREMULT : + HWC_BLENDING_COVERAGE); } - // scaling is already applied in mTransformedBounds - hwcl->displayFrame.left = mTransformedBounds.left; - hwcl->displayFrame.top = mTransformedBounds.top; - hwcl->displayFrame.right = mTransformedBounds.right; - hwcl->displayFrame.bottom = mTransformedBounds.bottom; - hwcl->visibleRegionScreen.rects = - reinterpret_cast<hwc_rect_t const *>( - visibleRegionScreen.getArray( - &hwcl->visibleRegionScreen.numRects)); + const Transform& tr = hw->getTransform(); + Rect transformedBounds(computeBounds()); + transformedBounds = tr.transform(transformedBounds); + + // scaling is already applied in transformedBounds + layer.setFrame(transformedBounds); + layer.setCrop(transformedBounds.getBounds()); + layer.setVisibleRegionScreen(tr.transform(visibleRegion)); +} - hwcl->sourceCrop.left = 0; - hwcl->sourceCrop.top = 0; - hwcl->sourceCrop.right = mTransformedBounds.width(); - hwcl->sourceCrop.bottom = mTransformedBounds.height(); +void LayerBase::setPerFrameData(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer) { + layer.setBuffer(0); } -void LayerBase::setPerFrameData(hwc_layer_t* hwcl) { - hwcl->compositionType = HWC_FRAMEBUFFER; - hwcl->handle = NULL; +void LayerBase::setAcquireFence(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer) { + layer.setAcquireFenceFd(-1); } void LayerBase::setFiltering(bool filtering) @@ -335,44 +311,41 @@ bool LayerBase::getFiltering() const return mFiltering; } -void LayerBase::draw(const Region& clip) const +void LayerBase::draw(const sp<const DisplayDevice>& hw, const Region& clip) const { - onDraw(clip); + onDraw(hw, clip); } -void LayerBase::drawForSreenShot() +void LayerBase::draw(const sp<const DisplayDevice>& hw) { - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - setFiltering(true); - onDraw( Region(hw.bounds()) ); - setFiltering(false); + onDraw( hw, Region(hw->bounds()) ); } -void LayerBase::clearWithOpenGL(const Region& clip, GLclampf red, - GLclampf green, GLclampf blue, - GLclampf alpha) const +void LayerBase::clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip, + GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) const { - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - const uint32_t fbHeight = hw.getHeight(); + const uint32_t fbHeight = hw->getHeight(); glColor4f(red,green,blue,alpha); glDisable(GL_TEXTURE_EXTERNAL_OES); glDisable(GL_TEXTURE_2D); glDisable(GL_BLEND); - glVertexPointer(2, GL_FLOAT, 0, mVertices); - glDrawArrays(GL_TRIANGLE_FAN, 0, mNumVertices); + LayerMesh mesh; + computeGeometry(hw, &mesh); + + glVertexPointer(2, GL_FLOAT, 0, mesh.getVertices()); + glDrawArrays(GL_TRIANGLE_FAN, 0, mesh.getVertexCount()); } -void LayerBase::clearWithOpenGL(const Region& clip) const +void LayerBase::clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip) const { - clearWithOpenGL(clip,0,0,0,0); + clearWithOpenGL(hw, clip, 0,0,0,0); } -void LayerBase::drawWithOpenGL(const Region& clip) const +void LayerBase::drawWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip) const { - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - const uint32_t fbHeight = hw.getHeight(); + const uint32_t fbHeight = hw->getHeight(); const State& s(drawingState()); GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA; @@ -397,6 +370,12 @@ void LayerBase::drawWithOpenGL(const Region& clip) const } } + LayerMesh mesh; + computeGeometry(hw, &mesh); + + // TODO: we probably want to generate the texture coords with the mesh + // here we assume that we only have 4 vertices + struct TexCoords { GLfloat u; GLfloat v; @@ -406,9 +385,9 @@ void LayerBase::drawWithOpenGL(const Region& clip) const if (!s.active.crop.isEmpty()) { crop = s.active.crop; } - GLfloat left = GLfloat(crop.left) / GLfloat(s.active.w); - GLfloat top = GLfloat(crop.top) / GLfloat(s.active.h); - GLfloat right = GLfloat(crop.right) / GLfloat(s.active.w); + GLfloat left = GLfloat(crop.left) / GLfloat(s.active.w); + GLfloat top = GLfloat(crop.top) / GLfloat(s.active.h); + GLfloat right = GLfloat(crop.right) / GLfloat(s.active.w); GLfloat bottom = GLfloat(crop.bottom) / GLfloat(s.active.h); TexCoords texCoords[4]; @@ -425,9 +404,9 @@ void LayerBase::drawWithOpenGL(const Region& clip) const } glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glVertexPointer(2, GL_FLOAT, 0, mVertices); glTexCoordPointer(2, GL_FLOAT, 0, texCoords); - glDrawArrays(GL_TRIANGLE_FAN, 0, mNumVertices); + glVertexPointer(2, GL_FLOAT, 0, mesh.getVertices()); + glDrawArrays(GL_TRIANGLE_FAN, 0, mesh.getVertexCount()); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisable(GL_BLEND); @@ -443,15 +422,14 @@ void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const result.append(buffer); s.transparentRegion.dump(result, "transparentRegion"); - transparentRegionScreen.dump(result, "transparentRegionScreen"); - visibleRegionScreen.dump(result, "visibleRegionScreen"); + visibleRegion.dump(result, "visibleRegion"); snprintf(buffer, SIZE, " " - "z=%9d, pos=(%g,%g), size=(%4d,%4d), crop=(%4d,%4d,%4d,%4d), " + "layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), crop=(%4d,%4d,%4d,%4d), " "isOpaque=%1d, needsDithering=%1d, invalidate=%1d, " "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n", - s.z, s.transform.tx(), s.transform.ty(), s.active.w, s.active.h, + s.z, s.layerStack, s.transform.tx(), s.transform.ty(), s.active.w, s.active.h, s.active.crop.left, s.active.crop.top, s.active.crop.right, s.active.crop.bottom, isOpaque(), needsDithering(), contentDirty, @@ -471,6 +449,14 @@ void LayerBase::dumpStats(String8& result, char* scratch, size_t SIZE) const { void LayerBase::clearStats() { } +sp<LayerBaseClient> LayerBase::getLayerBaseClient() const { + return 0; +} + +sp<Layer> LayerBase::getLayer() const { + return 0; +} + // --------------------------------------------------------------------------- int32_t LayerBaseClient::sIdentity = 1; @@ -554,7 +540,7 @@ LayerBaseClient::LayerCleaner::LayerCleaner(const sp<SurfaceFlinger>& flinger, LayerBaseClient::LayerCleaner::~LayerCleaner() { // destroy client resources - mFlinger->destroySurface(mLayer); + mFlinger->onLayerDestroyed(mLayer); } // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h index c547a40..6394542 100644 --- a/services/surfaceflinger/LayerBase.h +++ b/services/surfaceflinger/LayerBase.h @@ -25,6 +25,7 @@ #include <GLES/gl.h> #include <utils/RefBase.h> +#include <utils/String8.h> #include <ui/Region.h> @@ -32,19 +33,16 @@ #include <private/gui/LayerState.h> -#include <hardware/hwcomposer.h> - -#include "DisplayHardware/DisplayHardware.h" #include "Transform.h" +#include "DisplayHardware/HWComposer.h" namespace android { // --------------------------------------------------------------------------- class Client; -class DisplayHardware; +class DisplayDevice; class GraphicBuffer; -class GraphicPlane; class Layer; class LayerBaseClient; class SurfaceFlinger; @@ -60,9 +58,9 @@ public: DisplayID dpy; mutable bool contentDirty; - Region visibleRegionScreen; - Region transparentRegionScreen; - Region coveredRegionScreen; + // regions below are in window-manager space + Region visibleRegion; + Region coveredRegion; int32_t sequence; struct Geometry { @@ -81,6 +79,7 @@ public: Geometry active; Geometry requested; uint32_t z; + uint32_t layerStack; uint8_t alpha; uint8_t flags; uint8_t reserved[2]; @@ -89,6 +88,20 @@ public: Region transparentRegion; }; + class LayerMesh { + friend class LayerBase; + GLfloat mVertices[4][2]; + size_t mNumVertices; + public: + LayerMesh() : mNumVertices(4) { } + GLfloat const* getVertices() const { + return &mVertices[0][0]; + } + size_t getVertexCount() const { + return mNumVertices; + } + }; + virtual void setName(const String8& name); String8 getName() const; @@ -101,24 +114,30 @@ public: bool setTransparentRegionHint(const Region& opaque); bool setFlags(uint8_t flags, uint8_t mask); bool setCrop(const Rect& crop); - + bool setLayerStack(uint32_t layerStack); + void commitTransaction(); bool requestTransaction(); void forceVisibilityTransaction(); uint32_t getTransactionFlags(uint32_t flags); uint32_t setTransactionFlags(uint32_t flags); - - Rect visibleBounds() const; - virtual sp<LayerBaseClient> getLayerBaseClient() const { return 0; } - virtual sp<Layer> getLayer() const { return 0; } + void computeGeometry(const sp<const DisplayDevice>& hw, LayerMesh* mesh) const; + Rect computeBounds() const; - virtual const char* getTypeId() const { return "LayerBase"; } - virtual void setGeometry(hwc_layer_t* hwcl); - virtual void setPerFrameData(hwc_layer_t* hwcl); + virtual sp<LayerBaseClient> getLayerBaseClient() const; + virtual sp<Layer> getLayer() const; + + virtual const char* getTypeId() const { return "LayerBase"; } + virtual void setGeometry(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer); + virtual void setPerFrameData(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer); + virtual void setAcquireFence(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer); /** * draw - performs some global clipping optimizations @@ -126,13 +145,13 @@ public: * Typically this method is not overridden, instead implement onDraw() * to perform the actual drawing. */ - virtual void draw(const Region& clip) const; - virtual void drawForSreenShot(); + virtual void draw(const sp<const DisplayDevice>& hw, const Region& clip) const; + virtual void draw(const sp<const DisplayDevice>& hw); /** * onDraw - draws the surface. */ - virtual void onDraw(const Region& clip) const = 0; + virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const = 0; /** * initStates - called just after construction @@ -159,26 +178,13 @@ public: virtual void setCoveredRegion(const Region& coveredRegion); /** - * validateVisibility - cache a bunch of things - */ - virtual void validateVisibility(const Transform& globalTransform); - - /** - * lockPageFlip - called each time the screen is redrawn and returns whether + * latchBuffer - called each time the screen is redrawn and returns whether * the visible regions need to be recomputed (this is a fairly heavy * operation, so this should be set only if needed). Typically this is used * to figure out if the content or size of a surface has changed. */ - virtual void lockPageFlip(bool& recomputeVisibleRegions); - - /** - * unlockPageFlip - called each time the screen is redrawn. updates the - * final dirty region wrt the planeTransform. - * At this point, all visible regions, surface position and size, etc... are - * correct. - */ - virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion); - + virtual Region latchBuffer(bool& recomputeVisibleRegions); + /** * isOpaque - true if this surface is opaque */ @@ -212,13 +218,18 @@ public: /** called after page-flip */ - virtual void onLayerDisplayed() { } + virtual void onLayerDisplayed(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface* layer) { } /** called before composition. * returns true if the layer has pending updates. */ virtual bool onPreComposition() { return false; } + /** called before composition. + */ + virtual void onPostComposition() { } + /** always call base class first */ virtual void dump(String8& result, char* scratch, size_t size) const; virtual void shortDump(String8& result, char* scratch, size_t size) const; @@ -236,43 +247,27 @@ public: inline const State& currentState() const { return mCurrentState; } inline State& currentState() { return mCurrentState; } - int32_t getOrientation() const { return mOrientation; } - int32_t getPlaneOrientation() const { return mPlaneOrientation; } + void clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip) const; - void clearWithOpenGL(const Region& clip) const; + void setFiltering(bool filtering); + bool getFiltering() const; protected: - const GraphicPlane& graphicPlane(int dpy) const; - GraphicPlane& graphicPlane(int dpy); - - void clearWithOpenGL(const Region& clip, GLclampf r, GLclampf g, - GLclampf b, GLclampf alpha) const; - void drawWithOpenGL(const Region& clip) const; - - void setFiltering(bool filtering); - bool getFiltering() const; + void clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip, + GLclampf r, GLclampf g, GLclampf b, GLclampf alpha) const; + void drawWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip) const; sp<SurfaceFlinger> mFlinger; - uint32_t mFlags; private: // accessed only in the main thread // Whether filtering is forced on or not bool mFiltering; - // cached during validateVisibility() // Whether filtering is needed b/c of the drawingstate bool mNeedsFiltering; protected: - // cached during validateVisibility() - int32_t mOrientation; - int32_t mPlaneOrientation; - Transform mTransform; - GLfloat mVertices[4][2]; - size_t mNumVertices; - Rect mTransformedBounds; - // these are protected by an external lock State mCurrentState; State mDrawingState; diff --git a/services/surfaceflinger/LayerDim.cpp b/services/surfaceflinger/LayerDim.cpp index 96a310f..087d851 100644 --- a/services/surfaceflinger/LayerDim.cpp +++ b/services/surfaceflinger/LayerDim.cpp @@ -18,6 +18,9 @@ #include <stdint.h> #include <sys/types.h> +#include <GLES/gl.h> +#include <GLES/glext.h> + #include <utils/Errors.h> #include <utils/Log.h> @@ -25,7 +28,7 @@ #include "LayerDim.h" #include "SurfaceFlinger.h" -#include "DisplayHardware/DisplayHardware.h" +#include "DisplayDevice.h" namespace android { // --------------------------------------------------------------------------- @@ -40,13 +43,12 @@ LayerDim::~LayerDim() { } -void LayerDim::onDraw(const Region& clip) const +void LayerDim::onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const { const State& s(drawingState()); if (s.alpha>0) { - const DisplayHardware& hw(graphicPlane(0).displayHardware()); const GLfloat alpha = s.alpha/255.0f; - const uint32_t fbHeight = hw.getHeight(); + const uint32_t fbHeight = hw->getHeight(); glDisable(GL_TEXTURE_EXTERNAL_OES); glDisable(GL_TEXTURE_2D); @@ -59,8 +61,11 @@ void LayerDim::onDraw(const Region& clip) const glColor4f(0, 0, 0, alpha); - glVertexPointer(2, GL_FLOAT, 0, mVertices); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + LayerMesh mesh; + computeGeometry(hw, &mesh); + + glVertexPointer(2, GL_FLOAT, 0, mesh.getVertices()); + glDrawArrays(GL_TRIANGLE_FAN, 0, mesh.getVertexCount()); glDisable(GL_BLEND); glDisableClientState(GL_TEXTURE_COORD_ARRAY); diff --git a/services/surfaceflinger/LayerDim.h b/services/surfaceflinger/LayerDim.h index 8770e6d..fbfb2fb 100644 --- a/services/surfaceflinger/LayerDim.h +++ b/services/surfaceflinger/LayerDim.h @@ -36,7 +36,7 @@ public: const sp<Client>& client); virtual ~LayerDim(); - virtual void onDraw(const Region& clip) const; + virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const; virtual bool isOpaque() const { return false; } virtual bool isSecure() const { return false; } virtual bool isProtectedByApp() const { return false; } diff --git a/services/surfaceflinger/LayerScreenshot.cpp b/services/surfaceflinger/LayerScreenshot.cpp index b42353c..799ecdc 100644 --- a/services/surfaceflinger/LayerScreenshot.cpp +++ b/services/surfaceflinger/LayerScreenshot.cpp @@ -18,6 +18,9 @@ #include <stdint.h> #include <sys/types.h> +#include <GLES/gl.h> +#include <GLES/glext.h> + #include <utils/Errors.h> #include <utils/Log.h> @@ -25,7 +28,7 @@ #include "LayerScreenshot.h" #include "SurfaceFlinger.h" -#include "DisplayHardware/DisplayHardware.h" +#include "DisplayDevice.h" namespace android { @@ -41,8 +44,7 @@ LayerScreenshot::LayerScreenshot(SurfaceFlinger* flinger, DisplayID display, LayerScreenshot::~LayerScreenshot() { if (mTextureName) { - mFlinger->postMessageAsync( - new SurfaceFlinger::MessageDestroyGLTexture(mTextureName) ); + mFlinger->deleteTextureAsync(mTextureName); } } @@ -78,25 +80,25 @@ void LayerScreenshot::initTexture(GLfloat u, GLfloat v) { void LayerScreenshot::initStates(uint32_t w, uint32_t h, uint32_t flags) { LayerBaseClient::initStates(w, h, flags); - if (!(flags & ISurfaceComposer::eHidden)) { + if (!(flags & ISurfaceComposerClient::eHidden)) { capture(); } } uint32_t LayerScreenshot::doTransaction(uint32_t flags) { - const Layer::State& draw(drawingState()); - const Layer::State& curr(currentState()); + const LayerBase::State& draw(drawingState()); + const LayerBase::State& curr(currentState()); - if (draw.flags & ISurfaceComposer::eLayerHidden) { - if (!(curr.flags & ISurfaceComposer::eLayerHidden)) { + if (draw.flags & layer_state_t::eLayerHidden) { + if (!(curr.flags & layer_state_t::eLayerHidden)) { // we're going from hidden to visible status_t err = captureLocked(); if (err != NO_ERROR) { ALOGW("createScreenshotSurface failed (%s)", strerror(-err)); } } - } else if (curr.flags & ISurfaceComposer::eLayerHidden) { + } else if (curr.flags & layer_state_t::eLayerHidden) { // we're going from visible to hidden if (mTextureName) { glDeleteTextures(1, &mTextureName); @@ -106,13 +108,12 @@ uint32_t LayerScreenshot::doTransaction(uint32_t flags) return LayerBaseClient::doTransaction(flags); } -void LayerScreenshot::onDraw(const Region& clip) const +void LayerScreenshot::onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const { const State& s(drawingState()); if (s.alpha>0) { - const DisplayHardware& hw(graphicPlane(0).displayHardware()); const GLfloat alpha = s.alpha/255.0f; - const uint32_t fbHeight = hw.getHeight(); + const uint32_t fbHeight = hw->getHeight(); if (s.alpha == 0xFF) { glDisable(GL_BLEND); @@ -121,6 +122,9 @@ void LayerScreenshot::onDraw(const Region& clip) const glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } + LayerMesh mesh; + computeGeometry(hw, &mesh); + glColor4f(0, 0, 0, alpha); glDisable(GL_TEXTURE_EXTERNAL_OES); @@ -134,8 +138,8 @@ void LayerScreenshot::onDraw(const Region& clip) const glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(2, GL_FLOAT, 0, mTexCoords); - glVertexPointer(2, GL_FLOAT, 0, mVertices); - glDrawArrays(GL_TRIANGLE_FAN, 0, mNumVertices); + glVertexPointer(2, GL_FLOAT, 0, mesh.getVertices()); + glDrawArrays(GL_TRIANGLE_FAN, 0, mesh.getVertexCount()); glDisable(GL_BLEND); glDisable(GL_TEXTURE_2D); diff --git a/services/surfaceflinger/LayerScreenshot.h b/services/surfaceflinger/LayerScreenshot.h index ab90047..c06c23c 100644 --- a/services/surfaceflinger/LayerScreenshot.h +++ b/services/surfaceflinger/LayerScreenshot.h @@ -43,7 +43,7 @@ public: virtual void initStates(uint32_t w, uint32_t h, uint32_t flags); virtual uint32_t doTransaction(uint32_t flags); - virtual void onDraw(const Region& clip) const; + virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const; virtual bool isOpaque() const { return false; } virtual bool isSecure() const { return false; } virtual bool isProtectedByApp() const { return false; } diff --git a/services/surfaceflinger/MessageQueue.cpp b/services/surfaceflinger/MessageQueue.cpp index 290fff4..3f77f74 100644 --- a/services/surfaceflinger/MessageQueue.cpp +++ b/services/surfaceflinger/MessageQueue.cpp @@ -49,13 +49,13 @@ void MessageBase::handleMessage(const Message&) { // --------------------------------------------------------------------------- -void MessageQueue::Handler::signalRefresh() { +void MessageQueue::Handler::dispatchRefresh() { if ((android_atomic_or(eventMaskRefresh, &mEventMask) & eventMaskRefresh) == 0) { mQueue.mLooper->sendMessage(this, Message(MessageQueue::REFRESH)); } } -void MessageQueue::Handler::signalInvalidate() { +void MessageQueue::Handler::dispatchInvalidate() { if ((android_atomic_or(eventMaskInvalidate, &mEventMask) & eventMaskInvalidate) == 0) { mQueue.mLooper->sendMessage(this, Message(MessageQueue::INVALIDATE)); } @@ -132,13 +132,31 @@ status_t MessageQueue::postMessage( return NO_ERROR; } +/* when INVALIDATE_ON_VSYNC is set SF only processes + * buffer updates on VSYNC and performs a refresh immediately + * after. + * + * when INVALIDATE_ON_VSYNC is set to false, SF will instead + * perform the buffer updates immediately, but the refresh only + * at the next VSYNC. + * THIS MODE IS BUGGY ON GALAXY NEXUS AND WILL CAUSE HANGS + */ +#define INVALIDATE_ON_VSYNC 1 + void MessageQueue::invalidate() { -// mHandler->signalInvalidate(); +#if INVALIDATE_ON_VSYNC mEvents->requestNextVsync(); +#else + mHandler->dispatchInvalidate(); +#endif } void MessageQueue::refresh() { +#if INVALIDATE_ON_VSYNC + mHandler->dispatchRefresh(); +#else mEvents->requestNextVsync(); +#endif } int MessageQueue::cb_eventReceiver(int fd, int events, void* data) { @@ -152,7 +170,11 @@ int MessageQueue::eventReceiver(int fd, int events) { while ((n = DisplayEventReceiver::getEvents(mEventTube, buffer, 8)) > 0) { for (int i=0 ; i<n ; i++) { if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) { - mHandler->signalRefresh(); +#if INVALIDATE_ON_VSYNC + mHandler->dispatchInvalidate(); +#else + mHandler->dispatchRefresh(); +#endif break; } } diff --git a/services/surfaceflinger/MessageQueue.h b/services/surfaceflinger/MessageQueue.h index ea29e7e..710b2c2 100644 --- a/services/surfaceflinger/MessageQueue.h +++ b/services/surfaceflinger/MessageQueue.h @@ -70,8 +70,8 @@ class MessageQueue { public: Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) { } virtual void handleMessage(const Message& message); - void signalRefresh(); - void signalInvalidate(); + void dispatchRefresh(); + void dispatchInvalidate(); }; friend class Handler; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 51fcce4..c63d0cf 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -16,17 +16,13 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include <stdlib.h> -#include <stdio.h> #include <stdint.h> -#include <unistd.h> -#include <fcntl.h> +#include <sys/types.h> #include <errno.h> #include <math.h> -#include <limits.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/ioctl.h> + +#include <EGL/egl.h> +#include <GLES/gl.h> #include <cutils/log.h> #include <cutils/properties.h> @@ -36,20 +32,27 @@ #include <binder/MemoryHeapBase.h> #include <binder/PermissionCache.h> +#include <ui/DisplayInfo.h> + +#include <gui/BitTube.h> +#include <gui/BufferQueue.h> #include <gui/IDisplayEventConnection.h> +#include <gui/SurfaceTextureClient.h> + +#include <ui/GraphicBufferAllocator.h> +#include <ui/PixelFormat.h> #include <utils/String8.h> #include <utils/String16.h> #include <utils/StopWatch.h> #include <utils/Trace.h> -#include <ui/GraphicBufferAllocator.h> -#include <ui/PixelFormat.h> - -#include <GLES/gl.h> +#include <private/android_filesystem_config.h> #include "clz.h" #include "DdmConnection.h" +#include "DisplayDevice.h" +#include "Client.h" #include "EventThread.h" #include "GLExtensions.h" #include "Layer.h" @@ -57,12 +60,9 @@ #include "LayerScreenshot.h" #include "SurfaceFlinger.h" -#include "DisplayHardware/DisplayHardware.h" +#include "DisplayHardware/FramebufferSurface.h" #include "DisplayHardware/HWComposer.h" -#include <private/android_filesystem_config.h> -#include <private/gui/SharedBufferStack.h> -#include <gui/BitTube.h> #define EGL_VERSION_HW_ANDROID 0x3143 @@ -83,10 +83,10 @@ SurfaceFlinger::SurfaceFlinger() mTransactionFlags(0), mTransationPending(false), mLayersRemoved(false), + mRepaintEverything(0), mBootTime(systemTime()), mVisibleRegionsDirty(false), mHwWorkListDirty(false), - mElectronBeamAnimationMode(0), mDebugRegion(0), mDebugDDMS(0), mDebugDisableHWC(0), @@ -95,13 +95,7 @@ SurfaceFlinger::SurfaceFlinger() mLastSwapBufferTime(0), mDebugInTransaction(0), mLastTransactionTime(0), - mBootFinished(false), - mSecureFrameBuffer(0) -{ - init(); -} - -void SurfaceFlinger::init() + mBootFinished(false) { ALOGI("SurfaceFlinger is starting"); @@ -111,16 +105,14 @@ void SurfaceFlinger::init() property_get("debug.sf.showupdates", value, "0"); mDebugRegion = atoi(value); -#ifdef DDMS_DEBUGGING property_get("debug.sf.ddms", value, "0"); mDebugDDMS = atoi(value); if (mDebugDDMS) { DdmConnection::start(getServiceName()); } -#endif - ALOGI_IF(mDebugRegion, "showupdates enabled"); - ALOGI_IF(mDebugDDMS, "DDMS debugging enabled"); + ALOGI_IF(mDebugRegion, "showupdates enabled"); + ALOGI_IF(mDebugDDMS, "DDMS debugging enabled"); } void SurfaceFlinger::onFirstRef() @@ -136,7 +128,9 @@ void SurfaceFlinger::onFirstRef() SurfaceFlinger::~SurfaceFlinger() { - glDeleteTextures(1, &mWormholeTexName); + EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglTerminate(display); } void SurfaceFlinger::binderDied(const wp<IBinder>& who) @@ -145,17 +139,18 @@ void SurfaceFlinger::binderDied(const wp<IBinder>& who) // reset screen orientation Vector<ComposerState> state; - setTransactionState(state, eOrientationDefault, 0); + Vector<DisplayState> displays; + DisplayState d; + d.what = DisplayState::eOrientationChanged; + d.token = mDefaultDisplays[DisplayDevice::DISPLAY_ID_MAIN]; + d.orientation = DisplayState::eOrientationDefault; + displays.add(d); + setTransactionState(state, displays, 0); // restart the boot-animation startBootAnim(); } -sp<IMemoryHeap> SurfaceFlinger::getCblk() const -{ - return mServerHeap; -} - sp<ISurfaceComposerClient> SurfaceFlinger::createConnection() { sp<ISurfaceComposerClient> bclient; @@ -167,23 +162,43 @@ sp<ISurfaceComposerClient> SurfaceFlinger::createConnection() return bclient; } -sp<IGraphicBufferAlloc> SurfaceFlinger::createGraphicBufferAlloc() +sp<IBinder> SurfaceFlinger::createDisplay() { - sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc()); - return gba; + class DisplayToken : public BBinder { + sp<SurfaceFlinger> flinger; + virtual ~DisplayToken() { + // no more references, this display must be terminated + Mutex::Autolock _l(flinger->mStateLock); + flinger->mCurrentState.displays.removeItem(this); + flinger->setTransactionFlags(eDisplayTransactionNeeded); + } + public: + DisplayToken(const sp<SurfaceFlinger>& flinger) + : flinger(flinger) { + } + }; + + sp<BBinder> token = new DisplayToken(this); + + Mutex::Autolock _l(mStateLock); + DisplayDeviceState info(intptr_t(token.get())); // FIXME: we shouldn't use the address for the id + mCurrentState.displays.add(token, info); + + return token; } -const GraphicPlane& SurfaceFlinger::graphicPlane(int dpy) const -{ - ALOGE_IF(uint32_t(dpy) >= DISPLAY_COUNT, "Invalid DisplayID %d", dpy); - const GraphicPlane& plane(mGraphicPlanes[dpy]); - return plane; +sp<IBinder> SurfaceFlinger::getBuiltInDisplay(int32_t id) { + if (uint32_t(id) >= DisplayDevice::DISPLAY_ID_COUNT) { + ALOGE("getDefaultDisplay: id=%d is not a valid default display id", id); + return NULL; + } + return mDefaultDisplays[id]; } -GraphicPlane& SurfaceFlinger::graphicPlane(int dpy) +sp<IGraphicBufferAlloc> SurfaceFlinger::createGraphicBufferAlloc() { - return const_cast<GraphicPlane&>( - const_cast<SurfaceFlinger const *>(this)->graphicPlane(dpy)); + sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc()); + return gba; } void SurfaceFlinger::bootFinished() @@ -197,7 +212,7 @@ void SurfaceFlinger::bootFinished() const String16 name("window"); sp<IBinder> window(defaultServiceManager()->getService(name)); if (window != 0) { - window->linkToDeath(this); + window->linkToDeath(static_cast<IBinder::DeathRecipient*>(this)); } // stop boot animation @@ -206,60 +221,110 @@ void SurfaceFlinger::bootFinished() property_set("service.bootanim.exit", "1"); } -static inline uint16_t pack565(int r, int g, int b) { - return (r<<11)|(g<<5)|b; +void SurfaceFlinger::deleteTextureAsync(GLuint texture) { + class MessageDestroyGLTexture : public MessageBase { + GLuint texture; + public: + MessageDestroyGLTexture(GLuint texture) + : texture(texture) { + } + virtual bool handler() { + glDeleteTextures(1, &texture); + return true; + } + }; + postMessageAsync(new MessageDestroyGLTexture(texture)); +} + +status_t SurfaceFlinger::selectConfigForPixelFormat( + EGLDisplay dpy, + EGLint const* attrs, + PixelFormat format, + EGLConfig* outConfig) +{ + EGLConfig config = NULL; + EGLint numConfigs = -1, n=0; + eglGetConfigs(dpy, NULL, 0, &numConfigs); + EGLConfig* const configs = new EGLConfig[numConfigs]; + eglChooseConfig(dpy, attrs, configs, numConfigs, &n); + for (int i=0 ; i<n ; i++) { + EGLint nativeVisualId = 0; + eglGetConfigAttrib(dpy, configs[i], EGL_NATIVE_VISUAL_ID, &nativeVisualId); + if (nativeVisualId>0 && format == nativeVisualId) { + *outConfig = configs[i]; + delete [] configs; + return NO_ERROR; + } + } + delete [] configs; + return NAME_NOT_FOUND; } -status_t SurfaceFlinger::readyToRun() -{ - ALOGI( "SurfaceFlinger's main thread ready to run. " - "Initializing graphics H/W..."); +EGLConfig SurfaceFlinger::selectEGLConfig(EGLDisplay display, EGLint nativeVisualId) { + // select our EGLConfig. It must support EGL_RECORDABLE_ANDROID if + // it is to be used with WIFI displays + EGLConfig config; + EGLint dummy; + status_t err; + EGLint attribs[] = { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RECORDABLE_ANDROID, EGL_TRUE, + EGL_NONE + }; + err = selectConfigForPixelFormat(display, attribs, nativeVisualId, &config); + if (err) { + // maybe we failed because of EGL_RECORDABLE_ANDROID + ALOGW("couldn't find an EGLConfig with EGL_RECORDABLE_ANDROID"); + attribs[2] = EGL_NONE; + err = selectConfigForPixelFormat(display, attribs, nativeVisualId, &config); + } + ALOGE_IF(err, "couldn't find an EGLConfig matching the screen format"); + if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy) == EGL_TRUE) { + ALOGW_IF(dummy == EGL_SLOW_CONFIG, "EGL_SLOW_CONFIG selected!"); + } + return config; +} + +EGLContext SurfaceFlinger::createGLContext(EGLDisplay display, EGLConfig config) { + // Also create our EGLContext + EGLint contextAttributes[] = { +#ifdef EGL_IMG_context_priority +#ifdef HAS_CONTEXT_PRIORITY +#warning "using EGL_IMG_context_priority" + EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG, +#endif +#endif + EGL_NONE, EGL_NONE + }; + EGLContext ctxt = eglCreateContext(display, config, NULL, contextAttributes); + ALOGE_IF(ctxt==EGL_NO_CONTEXT, "EGLContext creation failed"); + return ctxt; +} + +void SurfaceFlinger::initializeGL(EGLDisplay display, EGLSurface surface) { + EGLBoolean result = eglMakeCurrent(display, surface, surface, mEGLContext); + if (!result) { + ALOGE("Couldn't create a working GLES context. check logs. exiting..."); + exit(0); + } + + GLExtensions& extensions(GLExtensions::getInstance()); + extensions.initWithGLStrings( + glGetString(GL_VENDOR), + glGetString(GL_RENDERER), + glGetString(GL_VERSION), + glGetString(GL_EXTENSIONS), + eglQueryString(display, EGL_VENDOR), + eglQueryString(display, EGL_VERSION), + eglQueryString(display, EGL_EXTENSIONS)); + + EGLint w, h; + eglQuerySurface(display, surface, EGL_WIDTH, &w); + eglQuerySurface(display, surface, EGL_HEIGHT, &h); + + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); + glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims); - // we only support one display currently - int dpy = 0; - - { - // initialize the main display - GraphicPlane& plane(graphicPlane(dpy)); - DisplayHardware* const hw = new DisplayHardware(this, dpy); - plane.setDisplayHardware(hw); - } - - // create the shared control-block - mServerHeap = new MemoryHeapBase(4096, - MemoryHeapBase::READ_ONLY, "SurfaceFlinger read-only heap"); - ALOGE_IF(mServerHeap==0, "can't create shared memory dealer"); - - mServerCblk = static_cast<surface_flinger_cblk_t*>(mServerHeap->getBase()); - ALOGE_IF(mServerCblk==0, "can't get to shared control block's address"); - - new(mServerCblk) surface_flinger_cblk_t; - - // initialize primary screen - // (other display should be initialized in the same manner, but - // asynchronously, as they could come and go. None of this is supported - // yet). - const GraphicPlane& plane(graphicPlane(dpy)); - const DisplayHardware& hw = plane.displayHardware(); - const uint32_t w = hw.getWidth(); - const uint32_t h = hw.getHeight(); - const uint32_t f = hw.getFormat(); - hw.makeCurrent(); - - // initialize the shared control block - mServerCblk->connected |= 1<<dpy; - display_cblk_t* dcblk = mServerCblk->displays + dpy; - memset(dcblk, 0, sizeof(display_cblk_t)); - dcblk->w = plane.getWidth(); - dcblk->h = plane.getHeight(); - dcblk->format = f; - dcblk->orientation = ISurfaceComposer::eOrientationDefault; - dcblk->xdpi = hw.getDpiX(); - dcblk->ydpi = hw.getDpiY(); - dcblk->fps = hw.getRefreshRate(); - dcblk->density = hw.getDensity(); - - // Initialize OpenGL|ES glPixelStorei(GL_UNPACK_ALIGNMENT, 4); glPixelStorei(GL_PACK_ALIGNMENT, 4); glEnableClientState(GL_VERTEX_ARRAY); @@ -267,17 +332,11 @@ status_t SurfaceFlinger::readyToRun() glDisable(GL_DITHER); glDisable(GL_CULL_FACE); - const uint16_t g0 = pack565(0x0F,0x1F,0x0F); - const uint16_t g1 = pack565(0x17,0x2f,0x17); - const uint16_t wormholeTexData[4] = { g0, g1, g1, g0 }; - glGenTextures(1, &mWormholeTexName); - glBindTexture(GL_TEXTURE_2D, mWormholeTexName); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, - GL_RGB, GL_UNSIGNED_SHORT_5_6_5, wormholeTexData); + struct pack565 { + inline uint16_t operator() (int r, int g, int b) const { + return (r<<11)|(g<<5)|b; + } + } pack565; const uint16_t protTexData[] = { pack565(0x03, 0x03, 0x03) }; glGenTextures(1, &mProtectedTexName); @@ -295,16 +354,81 @@ status_t SurfaceFlinger::readyToRun() // put the origin in the left-bottom corner glOrthof(0, w, 0, h, 0, 1); // l=0, r=w ; b=0, t=h + // print some debugging info + EGLint r,g,b,a; + eglGetConfigAttrib(display, mEGLConfig, EGL_RED_SIZE, &r); + eglGetConfigAttrib(display, mEGLConfig, EGL_GREEN_SIZE, &g); + eglGetConfigAttrib(display, mEGLConfig, EGL_BLUE_SIZE, &b); + eglGetConfigAttrib(display, mEGLConfig, EGL_ALPHA_SIZE, &a); + ALOGI("EGL informations:"); + ALOGI("vendor : %s", extensions.getEglVendor()); + ALOGI("version : %s", extensions.getEglVersion()); + ALOGI("extensions: %s", extensions.getEglExtension()); + ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported"); + ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, mEGLConfig); + ALOGI("OpenGL ES informations:"); + ALOGI("vendor : %s", extensions.getVendor()); + ALOGI("renderer : %s", extensions.getRenderer()); + ALOGI("version : %s", extensions.getVersion()); + ALOGI("extensions: %s", extensions.getExtension()); + ALOGI("GL_MAX_TEXTURE_SIZE = %d", mMaxTextureSize); + ALOGI("GL_MAX_VIEWPORT_DIMS = %d x %d", mMaxViewportDims[0], mMaxViewportDims[1]); +} + +status_t SurfaceFlinger::readyToRun() +{ + ALOGI( "SurfaceFlinger's main thread ready to run. " + "Initializing graphics H/W..."); + + // initialize EGL + mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + eglInitialize(mEGLDisplay, NULL, NULL); + + // Initialize the main display + // create native window to main display + sp<FramebufferSurface> fbs = FramebufferSurface::create(); + if (fbs == NULL) { + ALOGE("Display subsystem failed to initialize. check logs. exiting..."); + exit(0); + } + + sp<SurfaceTextureClient> stc(new SurfaceTextureClient( + static_cast<sp<ISurfaceTexture> >(fbs->getBufferQueue()))); + + // initialize the config and context + int format; + ANativeWindow* const anw = stc.get(); + anw->query(anw, NATIVE_WINDOW_FORMAT, &format); + mEGLConfig = selectEGLConfig(mEGLDisplay, format); + mEGLContext = createGLContext(mEGLDisplay, mEGLConfig); + + // initialize our main display hardware + + for (size_t i=0 ; i<DisplayDevice::DISPLAY_ID_COUNT ; i++) { + mDefaultDisplays[i] = new BBinder(); + mCurrentState.displays.add(mDefaultDisplays[i], DisplayDeviceState(i)); + } + sp<DisplayDevice> hw = new DisplayDevice(this, + DisplayDevice::DISPLAY_ID_MAIN, anw, fbs, mEGLConfig); + mDisplays.add(hw->getDisplayId(), hw); + + // initialize OpenGL ES + EGLSurface surface = hw->getEGLSurface(); + initializeGL(mEGLDisplay, surface); // start the EventThread mEventThread = new EventThread(this); mEventQueue.setEventThread(mEventThread); - hw.startSleepManagement(); - /* - * We're now ready to accept clients... - */ + // initialize the H/W composer + mHwc = new HWComposer(this, + *static_cast<HWComposer::EventHandler *>(this), + fbs->getFbHal()); + // initialize our drawing state + mDrawingState = mCurrentState; + + // We're now ready to accept clients... mReadyToRunBarrier.open(); // start boot animation @@ -319,6 +443,15 @@ void SurfaceFlinger::startBootAnim() { property_set("ctl.start", "bootanim"); } +uint32_t SurfaceFlinger::getMaxTextureSize() const { + return mMaxTextureSize; +} + +uint32_t SurfaceFlinger::getMaxViewportDims() const { + return mMaxViewportDims[0] < mMaxViewportDims[1] ? + mMaxViewportDims[0] : mMaxViewportDims[1]; +} + // ---------------------------------------------------------------------------- bool SurfaceFlinger::authenticateSurfaceTexture( @@ -362,12 +495,93 @@ bool SurfaceFlinger::authenticateSurfaceTexture( return false; } +status_t SurfaceFlinger::getDisplayInfo(DisplayID dpy, DisplayInfo* info) { + // TODO: this is here only for compatibility -- should go away eventually. + if (uint32_t(dpy) >= 1) { + return BAD_INDEX; + } + + const HWComposer& hwc(getHwComposer()); + float xdpi = hwc.getDpiX(); + float ydpi = hwc.getDpiY(); + + // TODO: Not sure if display density should handled by SF any longer + class Density { + static int getDensityFromProperty(char const* propName) { + char property[PROPERTY_VALUE_MAX]; + int density = 0; + if (property_get(propName, property, NULL) > 0) { + density = atoi(property); + } + return density; + } + public: + static int getEmuDensity() { + return getDensityFromProperty("qemu.sf.lcd_density"); } + static int getBuildDensity() { + return getDensityFromProperty("ro.sf.lcd_density"); } + }; + // The density of the device is provided by a build property + float density = Density::getBuildDensity() / 160.0f; + if (density == 0) { + // the build doesn't provide a density -- this is wrong! + // use xdpi instead + ALOGE("ro.sf.lcd_density must be defined as a build property"); + density = xdpi / 160.0f; + } + if (Density::getEmuDensity()) { + // if "qemu.sf.lcd_density" is specified, it overrides everything + xdpi = ydpi = density = Density::getEmuDensity(); + density /= 160.0f; + } + + sp<const DisplayDevice> hw(getDefaultDisplayDevice()); + info->w = hw->getWidth(); + info->h = hw->getHeight(); + info->xdpi = xdpi; + info->ydpi = ydpi; + info->fps = float(1e9 / hwc.getRefreshPeriod()); + info->density = density; + info->orientation = hw->getOrientation(); + // TODO: this needs to go away (currently needed only by webkit) + getPixelFormatInfo(hw->getFormat(), &info->pixelFormatInfo); + return NO_ERROR; +} + // ---------------------------------------------------------------------------- sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() { return mEventThread->createEventConnection(); } +void SurfaceFlinger::connectDisplay(const sp<ISurfaceTexture> surface) { + + sp<IBinder> token; + { // scope for the lock + Mutex::Autolock _l(mStateLock); + token = mExtDisplayToken; + } + + if (token == 0) { + token = createDisplay(); + } + + { // scope for the lock + Mutex::Autolock _l(mStateLock); + if (surface == 0) { + // release our current display. we're guarantee to have + // a reference to it (token), while we hold the lock + mExtDisplayToken = 0; + } else { + mExtDisplayToken = token; + } + + DisplayDeviceState& info(mCurrentState.displays.editValueFor(token)); + info.surface = surface; + setTransactionFlags(eDisplayTransactionNeeded); + } +} + // ---------------------------------------------------------------------------- void SurfaceFlinger::waitForEvent() { @@ -400,83 +614,262 @@ status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg, return res; } -bool SurfaceFlinger::threadLoop() -{ +bool SurfaceFlinger::threadLoop() { waitForEvent(); return true; } -void SurfaceFlinger::onMessageReceived(int32_t what) -{ +void SurfaceFlinger::onVSyncReceived(int dpy, nsecs_t timestamp) { + mEventThread->onVSyncReceived(dpy, timestamp); +} + +void SurfaceFlinger::eventControl(int event, int enabled) { + getHwComposer().eventControl(event, enabled); +} + +void SurfaceFlinger::onMessageReceived(int32_t what) { ATRACE_CALL(); switch (what) { - case MessageQueue::REFRESH: { -// case MessageQueue::INVALIDATE: { - // if we're in a global transaction, don't do anything. - const uint32_t mask = eTransactionNeeded | eTraversalNeeded; - uint32_t transactionFlags = peekTransactionFlags(mask); - if (CC_UNLIKELY(transactionFlags)) { - handleTransaction(transactionFlags); + case MessageQueue::INVALIDATE: + handleMessageTransaction(); + handleMessageInvalidate(); + signalRefresh(); + break; + case MessageQueue::REFRESH: + handleMessageRefresh(); + break; + } +} + +void SurfaceFlinger::handleMessageTransaction() { + uint32_t transactionFlags = peekTransactionFlags(eTransactionMask); + if (transactionFlags) { + handleTransaction(transactionFlags); + } +} + +void SurfaceFlinger::handleMessageInvalidate() { + ATRACE_CALL(); + handlePageFlip(); +} + +void SurfaceFlinger::handleMessageRefresh() { + ATRACE_CALL(); + preComposition(); + rebuildLayerStacks(); + setUpHWComposer(); + doDebugFlashRegions(); + doComposition(); + postComposition(); +} + +void SurfaceFlinger::doDebugFlashRegions() +{ + // is debugging enabled + if (CC_LIKELY(!mDebugRegion)) + return; + + const bool repaintEverything = mRepaintEverything; + for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { + const sp<DisplayDevice>& hw(mDisplays[dpy]); + if (hw->canDraw()) { + // transform the dirty region into this screen's coordinate space + const Region dirtyRegion(hw->getDirtyRegion(repaintEverything)); + if (!dirtyRegion.isEmpty()) { + // redraw the whole screen + doComposeSurfaces(hw, Region(hw->bounds())); + + // and draw the dirty region + glDisable(GL_TEXTURE_EXTERNAL_OES); + glDisable(GL_TEXTURE_2D); + glDisable(GL_BLEND); + glColor4f(1, 0, 1, 1); + const int32_t height = hw->getHeight(); + Region::const_iterator it = dirtyRegion.begin(); + Region::const_iterator const end = dirtyRegion.end(); + while (it != end) { + const Rect& r = *it++; + GLfloat vertices[][2] = { + { r.left, height - r.top }, + { r.left, height - r.bottom }, + { r.right, height - r.bottom }, + { r.right, height - r.top } + }; + glVertexPointer(2, GL_FLOAT, 0, vertices); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + } + hw->compositionComplete(); + // FIXME + if (hw->getDisplayId() >= DisplayDevice::DISPLAY_ID_COUNT) { + eglSwapBuffers(mEGLDisplay, hw->getEGLSurface()); + } } + } + } - // post surfaces (if needed) - handlePageFlip(); + postFramebuffer(); -// signalRefresh(); -// -// } break; -// -// case MessageQueue::REFRESH: { + if (mDebugRegion > 1) { + usleep(mDebugRegion * 1000); + } +} - handleRefresh(); +void SurfaceFlinger::preComposition() +{ + bool needExtraInvalidate = false; + const LayerVector& currentLayers(mDrawingState.layersSortedByZ); + const size_t count = currentLayers.size(); + for (size_t i=0 ; i<count ; i++) { + if (currentLayers[i]->onPreComposition()) { + needExtraInvalidate = true; + } + } + if (needExtraInvalidate) { + signalLayerUpdate(); + } +} - const DisplayHardware& hw(graphicPlane(0).displayHardware()); +void SurfaceFlinger::postComposition() +{ + const LayerVector& currentLayers(mDrawingState.layersSortedByZ); + const size_t count = currentLayers.size(); + for (size_t i=0 ; i<count ; i++) { + currentLayers[i]->onPostComposition(); + } +} -// if (mDirtyRegion.isEmpty()) { -// return; -// } +void SurfaceFlinger::rebuildLayerStacks() { + // rebuild the visible layer list per screen + if (CC_UNLIKELY(mVisibleRegionsDirty)) { + ATRACE_CALL(); + mVisibleRegionsDirty = false; + invalidateHwcGeometry(); + const LayerVector& currentLayers(mDrawingState.layersSortedByZ); + for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { + const sp<DisplayDevice>& hw(mDisplays[dpy]); + Region opaqueRegion; + Region dirtyRegion; + computeVisibleRegions(currentLayers, + hw->getLayerStack(), dirtyRegion, opaqueRegion); + hw->dirtyRegion.orSelf(dirtyRegion); - if (CC_UNLIKELY(mHwWorkListDirty)) { - // build the h/w work list - handleWorkList(); + Vector< sp<LayerBase> > layersSortedByZ; + const size_t count = currentLayers.size(); + for (size_t i=0 ; i<count ; i++) { + const Layer::State& s(currentLayers[i]->drawingState()); + if (s.layerStack == hw->getLayerStack()) { + if (!currentLayers[i]->visibleRegion.isEmpty()) { + layersSortedByZ.add(currentLayers[i]); + } + } } + hw->setVisibleLayersSortedByZ(layersSortedByZ); + hw->undefinedRegion.set(hw->getBounds()); + hw->undefinedRegion.subtractSelf( + hw->getTransform().transform(opaqueRegion)); + } + } +} - if (CC_LIKELY(hw.canDraw())) { - // repaint the framebuffer (if needed) - handleRepaint(); - // inform the h/w that we're done compositing - hw.compositionComplete(); - postFramebuffer(); - } else { - // pretend we did the post - hw.compositionComplete(); +void SurfaceFlinger::setUpHWComposer() { + HWComposer& hwc(getHwComposer()); + if (hwc.initCheck() == NO_ERROR) { + // build the h/w work list + const bool workListsDirty = mHwWorkListDirty; + mHwWorkListDirty = false; + for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { + sp<const DisplayDevice> hw(mDisplays[dpy]); + const Vector< sp<LayerBase> >& currentLayers( + hw->getVisibleLayersSortedByZ()); + const size_t count = currentLayers.size(); + + const int32_t id = hw->getDisplayId(); + if (hwc.createWorkList(id, count) >= 0) { + HWComposer::LayerListIterator cur = hwc.begin(id); + const HWComposer::LayerListIterator end = hwc.end(id); + for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) { + const sp<LayerBase>& layer(currentLayers[i]); + + if (CC_UNLIKELY(workListsDirty)) { + layer->setGeometry(hw, *cur); + if (mDebugDisableHWC || mDebugRegion) { + cur->setSkip(true); + } + } + + /* + * update the per-frame h/w composer data for each layer + * and build the transparent region of the FB + */ + layer->setPerFrameData(hw, *cur); + } } + } + status_t err = hwc.prepare(); + ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err)); + } +} - } break; +void SurfaceFlinger::doComposition() { + ATRACE_CALL(); + const bool repaintEverything = android_atomic_and(0, &mRepaintEverything); + for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { + const sp<DisplayDevice>& hw(mDisplays[dpy]); + if (hw->canDraw()) { + // transform the dirty region into this screen's coordinate space + const Region dirtyRegion(hw->getDirtyRegion(repaintEverything)); + if (!dirtyRegion.isEmpty()) { + // repaint the framebuffer (if needed) + doDisplayComposition(hw, dirtyRegion); + } + hw->dirtyRegion.clear(); + hw->flip(hw->swapRegion); + hw->swapRegion.clear(); + } + // inform the h/w that we're done compositing + hw->compositionComplete(); } + postFramebuffer(); } void SurfaceFlinger::postFramebuffer() { ATRACE_CALL(); - // mSwapRegion can be empty here is some cases, for instance if a hidden - // or fully transparent window is updating. - // in that case, we need to flip anyways to not risk a deadlock with - // h/w composer. - const DisplayHardware& hw(graphicPlane(0).displayHardware()); const nsecs_t now = systemTime(); mDebugInSwapBuffers = now; - hw.flip(mSwapRegion); - size_t numLayers = mVisibleLayersSortedByZ.size(); - for (size_t i = 0; i < numLayers; i++) { - mVisibleLayersSortedByZ[i]->onLayerDisplayed(); + HWComposer& hwc(getHwComposer()); + if (hwc.initCheck() == NO_ERROR) { + // FIXME: eventually commit() won't take arguments + // FIXME: EGL spec says: + // "surface must be bound to the calling thread's current context, + // for the current rendering API." + DisplayDevice::makeCurrent( + getDisplayDevice(DisplayDevice::DISPLAY_ID_MAIN), mEGLContext); + hwc.commit(mEGLDisplay, getDefaultDisplayDevice()->getEGLSurface()); + } + + for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { + sp<const DisplayDevice> hw(mDisplays[dpy]); + const Vector< sp<LayerBase> >& currentLayers(hw->getVisibleLayersSortedByZ()); + const size_t count = currentLayers.size(); + if (hwc.initCheck() == NO_ERROR) { + int32_t id = hw->getDisplayId(); + HWComposer::LayerListIterator cur = hwc.begin(id); + const HWComposer::LayerListIterator end = hwc.end(id); + for (size_t i = 0; cur != end && i < count; ++i, ++cur) { + currentLayers[i]->onLayerDisplayed(hw, &*cur); + } + } else { + for (size_t i = 0; i < count; i++) { + currentLayers[i]->onLayerDisplayed(hw, NULL); + } + } } mLastSwapBufferTime = systemTime() - now; mDebugInSwapBuffers = 0; - mSwapRegion.clear(); } void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) @@ -493,8 +886,7 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) // with mStateLock held to guarantee that mCurrentState won't change // until the transaction is committed. - const uint32_t mask = eTransactionNeeded | eTraversalNeeded; - transactionFlags = getTransactionFlags(mask); + transactionFlags = getTransactionFlags(eTransactionMask); handleTransactionLocked(transactionFlags); mLastTransactionTime = systemTime() - now; @@ -513,8 +905,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) * (perform the transaction for each of them if needed) */ - const bool layersNeedTransaction = transactionFlags & eTraversalNeeded; - if (layersNeedTransaction) { + if (transactionFlags & eTraversalNeeded) { for (size_t i=0 ; i<count ; i++) { const sp<LayerBase>& layer = currentLayers[i]; uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded); @@ -527,49 +918,107 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) } /* - * Perform our own transaction if needed + * Perform display own transactions if needed */ - if (transactionFlags & eTransactionNeeded) { - if (mCurrentState.orientation != mDrawingState.orientation) { - // the orientation has changed, recompute all visible regions - // and invalidate everything. - - const int dpy = 0; - const int orientation = mCurrentState.orientation; - // Currently unused: const uint32_t flags = mCurrentState.orientationFlags; - GraphicPlane& plane(graphicPlane(dpy)); - plane.setOrientation(orientation); - - // update the shared control block - const DisplayHardware& hw(plane.displayHardware()); - volatile display_cblk_t* dcblk = mServerCblk->displays + dpy; - dcblk->orientation = orientation; - dcblk->w = plane.getWidth(); - dcblk->h = plane.getHeight(); - + if (transactionFlags & eDisplayTransactionNeeded) { + // here we take advantage of Vector's copy-on-write semantics to + // improve performance by skipping the transaction entirely when + // know that the lists are identical + const KeyedVector< wp<IBinder>, DisplayDeviceState>& curr(mCurrentState.displays); + const KeyedVector< wp<IBinder>, DisplayDeviceState>& draw(mDrawingState.displays); + if (!curr.isIdenticalTo(draw)) { mVisibleRegionsDirty = true; - mDirtyRegion.set(hw.bounds()); - } + const size_t cc = curr.size(); + const size_t dc = draw.size(); + + // find the displays that were removed + // (ie: in drawing state but not in current state) + // also handle displays that changed + // (ie: displays that are in both lists) + for (size_t i=0 ; i<dc ; i++) { + const ssize_t j = curr.indexOfKey(draw.keyAt(i)); + if (j < 0) { + // in drawing state but not in current state + if (draw[i].id != DisplayDevice::DISPLAY_ID_MAIN) { + mDisplays.removeItem(draw[i].id); + } else { + ALOGW("trying to remove the main display"); + } + } else { + // this display is in both lists. see if something changed. + const DisplayDeviceState& state(curr[j]); + if (state.surface->asBinder() != draw[i].surface->asBinder()) { + // changing the surface is like destroying and + // recreating the DisplayDevice + + sp<SurfaceTextureClient> stc( + new SurfaceTextureClient(state.surface)); + + sp<DisplayDevice> disp = new DisplayDevice(this, + state.id, stc, 0, mEGLConfig); + + disp->setLayerStack(state.layerStack); + disp->setOrientation(state.orientation); + // TODO: take viewport and frame into account + mDisplays.replaceValueFor(state.id, disp); + } + if (state.layerStack != draw[i].layerStack) { + const sp<DisplayDevice>& disp(getDisplayDevice(state.id)); + disp->setLayerStack(state.layerStack); + } + if (state.orientation != draw[i].orientation || + state.viewport != draw[i].viewport || + state.frame != draw[i].frame) { + const sp<DisplayDevice>& disp(getDisplayDevice(state.id)); + disp->setOrientation(state.orientation); + // TODO: take viewport and frame into account + } + } + } - if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) { - // layers have been added - mVisibleRegionsDirty = true; + // find displays that were added + // (ie: in current state but not in drawing state) + for (size_t i=0 ; i<cc ; i++) { + if (draw.indexOfKey(curr.keyAt(i)) < 0) { + const DisplayDeviceState& state(curr[i]); + sp<SurfaceTextureClient> stc( + new SurfaceTextureClient(state.surface)); + sp<DisplayDevice> disp = new DisplayDevice(this, state.id, + stc, 0, mEGLConfig); + mDisplays.add(state.id, disp); + } + } } + } - // some layers might have been removed, so - // we need to update the regions they're exposing. - if (mLayersRemoved) { - mLayersRemoved = false; - mVisibleRegionsDirty = true; - const LayerVector& previousLayers(mDrawingState.layersSortedByZ); - const size_t count = previousLayers.size(); - for (size_t i=0 ; i<count ; i++) { - const sp<LayerBase>& layer(previousLayers[i]); - if (currentLayers.indexOf( layer ) < 0) { - // this layer is not visible anymore - mDirtyRegionRemovedLayer.orSelf(layer->visibleRegionScreen); - } + /* + * Perform our own transaction if needed + */ + + const LayerVector& previousLayers(mDrawingState.layersSortedByZ); + if (currentLayers.size() > previousLayers.size()) { + // layers have been added + mVisibleRegionsDirty = true; + } + + // some layers might have been removed, so + // we need to update the regions they're exposing. + if (mLayersRemoved) { + mLayersRemoved = false; + mVisibleRegionsDirty = true; + const size_t count = previousLayers.size(); + for (size_t i=0 ; i<count ; i++) { + const sp<LayerBase>& layer(previousLayers[i]); + if (currentLayers.indexOf(layer) < 0) { + // this layer is not visible anymore + // TODO: we could traverse the tree from front to back and + // compute the actual visible region + // TODO: we could cache the transformed region + Layer::State front(layer->drawingState()); + Region visibleReg = front.transform.transform( + Region(Rect(front.active.w, front.active.h))); + invalidateLayerStack(front.layerStack, visibleReg); } } } @@ -577,30 +1026,44 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) commitTransaction(); } +void SurfaceFlinger::commitTransaction() +{ + if (!mLayersPendingRemoval.isEmpty()) { + // Notify removed layers now that they can't be drawn from + for (size_t i = 0; i < mLayersPendingRemoval.size(); i++) { + mLayersPendingRemoval[i]->onRemoved(); + } + mLayersPendingRemoval.clear(); + } + + mDrawingState = mCurrentState; + mTransationPending = false; + mTransactionCV.broadcast(); +} + void SurfaceFlinger::computeVisibleRegions( - const LayerVector& currentLayers, Region& dirtyRegion, Region& opaqueRegion) + const LayerVector& currentLayers, uint32_t layerStack, + Region& outDirtyRegion, Region& outOpaqueRegion) { ATRACE_CALL(); - const GraphicPlane& plane(graphicPlane(0)); - const Transform& planeTransform(plane.transform()); - const DisplayHardware& hw(plane.displayHardware()); - const Region screenRegion(hw.bounds()); - Region aboveOpaqueLayers; Region aboveCoveredLayers; Region dirty; - bool secureFrameBuffer = false; + outDirtyRegion.clear(); size_t i = currentLayers.size(); while (i--) { const sp<LayerBase>& layer = currentLayers[i]; - layer->validateVisibility(planeTransform); // start with the whole surface at its current location const Layer::State& s(layer->drawingState()); + // only consider the layers on the given later stack + if (s.layerStack != layerStack) + continue; + /* * opaqueRegion: area of a surface that is fully opaque. */ @@ -622,19 +1085,32 @@ void SurfaceFlinger::computeVisibleRegions( // handle hidden surfaces by setting the visible region to empty - if (CC_LIKELY(!(s.flags & ISurfaceComposer::eLayerHidden) && s.alpha)) { + if (CC_LIKELY(!(s.flags & layer_state_t::eLayerHidden) && s.alpha)) { const bool translucent = !layer->isOpaque(); - const Rect bounds(layer->visibleBounds()); + Rect bounds(layer->computeBounds()); visibleRegion.set(bounds); - visibleRegion.andSelf(screenRegion); if (!visibleRegion.isEmpty()) { // Remove the transparent area from the visible region if (translucent) { - visibleRegion.subtractSelf(layer->transparentRegionScreen); + Region transparentRegionScreen; + const Transform tr(s.transform); + if (tr.transformed()) { + if (tr.preserveRects()) { + // transform the transparent region + transparentRegionScreen = tr.transform(s.transparentRegion); + } else { + // transformation too complex, can't do the + // transparent region optimization. + transparentRegionScreen.clear(); + } + } else { + transparentRegionScreen = s.transparentRegion; + } + visibleRegion.subtractSelf(transparentRegionScreen); } // compute the opaque region - const int32_t layerOrientation = layer->getOrientation(); + const int32_t layerOrientation = s.transform.getOrientation(); if (s.alpha==255 && !translucent && ((layerOrientation & Transform::ROT_INVALID) == false)) { // the opaque region is the layer's footprint @@ -657,7 +1133,7 @@ void SurfaceFlinger::computeVisibleRegions( // we need to invalidate the whole region dirty = visibleRegion; // as well, as the old visible region - dirty.orSelf(layer->visibleRegionScreen); + dirty.orSelf(layer->visibleRegion); layer->contentDirty = false; } else { /* compute the exposed region: @@ -673,15 +1149,15 @@ void SurfaceFlinger::computeVisibleRegions( * exposed because of a resize. */ const Region newExposed = visibleRegion - coveredRegion; - const Region oldVisibleRegion = layer->visibleRegionScreen; - const Region oldCoveredRegion = layer->coveredRegionScreen; + const Region oldVisibleRegion = layer->visibleRegion; + const Region oldCoveredRegion = layer->coveredRegion; const Region oldExposed = oldVisibleRegion - oldCoveredRegion; dirty = (visibleRegion&oldCoveredRegion) | (newExposed-oldExposed); } dirty.subtractSelf(aboveOpaqueLayers); // accumulate to the screen dirty region - dirtyRegion.orSelf(dirty); + outDirtyRegion.orSelf(dirty); // Update aboveOpaqueLayers for next (lower) layer aboveOpaqueLayers.orSelf(opaqueRegion); @@ -689,225 +1165,107 @@ void SurfaceFlinger::computeVisibleRegions( // Store the visible region is screen space layer->setVisibleRegion(visibleRegion); layer->setCoveredRegion(coveredRegion); - - // If a secure layer is partially visible, lock-down the screen! - if (layer->isSecure() && !visibleRegion.isEmpty()) { - secureFrameBuffer = true; - } } - // invalidate the areas where a layer was removed - dirtyRegion.orSelf(mDirtyRegionRemovedLayer); - mDirtyRegionRemovedLayer.clear(); - - mSecureFrameBuffer = secureFrameBuffer; - opaqueRegion = aboveOpaqueLayers; + outOpaqueRegion = aboveOpaqueLayers; } - -void SurfaceFlinger::commitTransaction() -{ - if (!mLayersPendingRemoval.isEmpty()) { - // Notify removed layers now that they can't be drawn from - for (size_t i = 0; i < mLayersPendingRemoval.size(); i++) { - mLayersPendingRemoval[i]->onRemoved(); +void SurfaceFlinger::invalidateLayerStack(uint32_t layerStack, + const Region& dirty) { + for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { + const sp<DisplayDevice>& hw(mDisplays[dpy]); + if (hw->getLayerStack() == layerStack) { + hw->dirtyRegion.orSelf(dirty); } - mLayersPendingRemoval.clear(); } - - mDrawingState = mCurrentState; - mTransationPending = false; - mTransactionCV.broadcast(); } void SurfaceFlinger::handlePageFlip() { - ATRACE_CALL(); - const DisplayHardware& hw = graphicPlane(0).displayHardware(); - const Region screenRegion(hw.bounds()); + Region dirtyRegion; - const LayerVector& currentLayers(mDrawingState.layersSortedByZ); - const bool visibleRegions = lockPageFlip(currentLayers); - - if (visibleRegions || mVisibleRegionsDirty) { - Region opaqueRegion; - computeVisibleRegions(currentLayers, mDirtyRegion, opaqueRegion); - - /* - * rebuild the visible layer list - */ - const size_t count = currentLayers.size(); - mVisibleLayersSortedByZ.clear(); - mVisibleLayersSortedByZ.setCapacity(count); - for (size_t i=0 ; i<count ; i++) { - if (!currentLayers[i]->visibleRegionScreen.isEmpty()) - mVisibleLayersSortedByZ.add(currentLayers[i]); - } - - mWormholeRegion = screenRegion.subtract(opaqueRegion); - mVisibleRegionsDirty = false; - invalidateHwcGeometry(); - } - - unlockPageFlip(currentLayers); - - mDirtyRegion.orSelf(getAndClearInvalidateRegion()); - mDirtyRegion.andSelf(screenRegion); -} - -void SurfaceFlinger::invalidateHwcGeometry() -{ - mHwWorkListDirty = true; -} - -bool SurfaceFlinger::lockPageFlip(const LayerVector& currentLayers) -{ - bool recomputeVisibleRegions = false; - size_t count = currentLayers.size(); - sp<LayerBase> const* layers = currentLayers.array(); - for (size_t i=0 ; i<count ; i++) { - const sp<LayerBase>& layer(layers[i]); - layer->lockPageFlip(recomputeVisibleRegions); - } - return recomputeVisibleRegions; -} - -void SurfaceFlinger::unlockPageFlip(const LayerVector& currentLayers) -{ - const GraphicPlane& plane(graphicPlane(0)); - const Transform& planeTransform(plane.transform()); - const size_t count = currentLayers.size(); - sp<LayerBase> const* layers = currentLayers.array(); - for (size_t i=0 ; i<count ; i++) { - const sp<LayerBase>& layer(layers[i]); - layer->unlockPageFlip(planeTransform, mDirtyRegion); - } -} - -void SurfaceFlinger::handleRefresh() -{ - bool needInvalidate = false; + bool visibleRegions = false; const LayerVector& currentLayers(mDrawingState.layersSortedByZ); const size_t count = currentLayers.size(); for (size_t i=0 ; i<count ; i++) { const sp<LayerBase>& layer(currentLayers[i]); - if (layer->onPreComposition()) { - needInvalidate = true; - } - } - if (needInvalidate) { - signalLayerUpdate(); + const Region dirty(layer->latchBuffer(visibleRegions)); + Layer::State s(layer->drawingState()); + invalidateLayerStack(s.layerStack, dirty); } -} + mVisibleRegionsDirty |= visibleRegions; +} -void SurfaceFlinger::handleWorkList() +void SurfaceFlinger::invalidateHwcGeometry() { - mHwWorkListDirty = false; - HWComposer& hwc(graphicPlane(0).displayHardware().getHwComposer()); - if (hwc.initCheck() == NO_ERROR) { - const Vector< sp<LayerBase> >& currentLayers(mVisibleLayersSortedByZ); - const size_t count = currentLayers.size(); - hwc.createWorkList(count); - hwc_layer_t* const cur(hwc.getLayers()); - for (size_t i=0 ; cur && i<count ; i++) { - currentLayers[i]->setGeometry(&cur[i]); - if (mDebugDisableHWC || mDebugRegion) { - cur[i].compositionType = HWC_FRAMEBUFFER; - cur[i].flags |= HWC_SKIP_LAYER; - } - } - } + mHwWorkListDirty = true; } -void SurfaceFlinger::handleRepaint() + +void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& hw, + const Region& inDirtyRegion) { - ATRACE_CALL(); + Region dirtyRegion(inDirtyRegion); // compute the invalid region - mSwapRegion.orSelf(mDirtyRegion); + hw->swapRegion.orSelf(dirtyRegion); - if (CC_UNLIKELY(mDebugRegion)) { - debugFlashRegions(); - } - - // set the frame buffer - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - uint32_t flags = hw.getFlags(); - if (flags & DisplayHardware::SWAP_RECTANGLE) { + uint32_t flags = hw->getFlags(); + if (flags & DisplayDevice::SWAP_RECTANGLE) { // we can redraw only what's dirty, but since SWAP_RECTANGLE only // takes a rectangle, we must make sure to update that whole // rectangle in that case - mDirtyRegion.set(mSwapRegion.bounds()); + dirtyRegion.set(hw->swapRegion.bounds()); } else { - if (flags & DisplayHardware::PARTIAL_UPDATES) { + if (flags & DisplayDevice::PARTIAL_UPDATES) { // We need to redraw the rectangle that will be updated // (pushed to the framebuffer). // This is needed because PARTIAL_UPDATES only takes one - // rectangle instead of a region (see DisplayHardware::flip()) - mDirtyRegion.set(mSwapRegion.bounds()); + // rectangle instead of a region (see DisplayDevice::flip()) + dirtyRegion.set(hw->swapRegion.bounds()); } else { // we need to redraw everything (the whole screen) - mDirtyRegion.set(hw.bounds()); - mSwapRegion = mDirtyRegion; + dirtyRegion.set(hw->bounds()); + hw->swapRegion = dirtyRegion; } } - setupHardwareComposer(); - composeSurfaces(mDirtyRegion); + doComposeSurfaces(hw, dirtyRegion); + + // FIXME: we need to call eglSwapBuffers() on displays that have + // GL composition and only on those. + // however, currently hwc.commit() already does that for the main + // display and never for the other ones + if (hw->getDisplayId() >= DisplayDevice::DISPLAY_ID_COUNT) { + // FIXME: EGL spec says: + // "surface must be bound to the calling thread's current context, + // for the current rendering API." + eglSwapBuffers(mEGLDisplay, hw->getEGLSurface()); + } // update the swap region and clear the dirty region - mSwapRegion.orSelf(mDirtyRegion); - mDirtyRegion.clear(); + hw->swapRegion.orSelf(dirtyRegion); } -void SurfaceFlinger::setupHardwareComposer() +void SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty) { - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - HWComposer& hwc(hw.getHwComposer()); - hwc_layer_t* const cur(hwc.getLayers()); - if (!cur) { - return; - } - - const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ); - size_t count = layers.size(); + HWComposer& hwc(getHwComposer()); + int32_t id = hw->getDisplayId(); + HWComposer::LayerListIterator cur = hwc.begin(id); + const HWComposer::LayerListIterator end = hwc.end(id); - ALOGE_IF(hwc.getNumLayers() != count, - "HAL number of layers (%d) doesn't match surfaceflinger (%d)", - hwc.getNumLayers(), count); - - // just to be extra-safe, use the smallest count - if (hwc.initCheck() == NO_ERROR) { - count = count < hwc.getNumLayers() ? count : hwc.getNumLayers(); - } + const size_t fbLayerCount = hwc.getLayerCount(id, HWC_FRAMEBUFFER); + if (cur==end || fbLayerCount) { - /* - * update the per-frame h/w composer data for each layer - * and build the transparent region of the FB - */ - for (size_t i=0 ; i<count ; i++) { - const sp<LayerBase>& layer(layers[i]); - layer->setPerFrameData(&cur[i]); - } - status_t err = hwc.prepare(); - ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err)); -} + DisplayDevice::makeCurrent(hw, mEGLContext); -void SurfaceFlinger::composeSurfaces(const Region& dirty) -{ - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - HWComposer& hwc(hw.getHwComposer()); - hwc_layer_t* const cur(hwc.getLayers()); + // set the frame buffer + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); - const size_t fbLayerCount = hwc.getLayerCount(HWC_FRAMEBUFFER); - if (!cur || fbLayerCount) { // Never touch the framebuffer if we don't have any framebuffer layers - - if (hwc.getLayerCount(HWC_OVERLAY)) { + if (hwc.getLayerCount(id, HWC_OVERLAY)) { // when using overlays, we assume a fully transparent framebuffer // NOTE: we could reduce how much we need to clear, for instance // remove where there are opaque FB layers. however, on some @@ -916,10 +1274,11 @@ void SurfaceFlinger::composeSurfaces(const Region& dirty) glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); } else { + const Region region(hw->undefinedRegion.intersect(dirty)); // screen is already cleared here - if (!mWormholeRegion.isEmpty()) { + if (!region.isEmpty()) { // can happen with SurfaceView - drawWormhole(); + drawWormhole(region); } } @@ -927,82 +1286,40 @@ void SurfaceFlinger::composeSurfaces(const Region& dirty) * and then, render the layers targeted at the framebuffer */ - const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ); + const Vector< sp<LayerBase> >& layers(hw->getVisibleLayersSortedByZ()); const size_t count = layers.size(); - - for (size_t i=0 ; i<count ; i++) { + const Transform& tr = hw->getTransform(); + for (size_t i=0 ; i<count ; ++i) { const sp<LayerBase>& layer(layers[i]); - const Region clip(dirty.intersect(layer->visibleRegionScreen)); - if (!clip.isEmpty()) { - if (cur && (cur[i].compositionType == HWC_OVERLAY)) { - if (i && (cur[i].hints & HWC_HINT_CLEAR_FB) - && layer->isOpaque()) { - // never clear the very first layer since we're - // guaranteed the FB is already cleared - layer->clearWithOpenGL(clip); + const Region clip(dirty.intersect(tr.transform(layer->visibleRegion))); + if (cur != end) { + // we're using h/w composer + if (!clip.isEmpty()) { + if (cur->getCompositionType() == HWC_OVERLAY) { + if (i && (cur->getHints() & HWC_HINT_CLEAR_FB) + && layer->isOpaque()) { + // never clear the very first layer since we're + // guaranteed the FB is already cleared + layer->clearWithOpenGL(hw, clip); + } + } else { + layer->draw(hw, clip); } - continue; + layer->setAcquireFence(hw, *cur); + } + ++cur; + } else { + // we're not using h/w composer + if (!clip.isEmpty()) { + layer->draw(hw, clip); } - // render the layer - layer->draw(clip); } } } } -void SurfaceFlinger::debugFlashRegions() -{ - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - const uint32_t flags = hw.getFlags(); - const int32_t height = hw.getHeight(); - if (mSwapRegion.isEmpty()) { - return; - } - - if (!(flags & DisplayHardware::SWAP_RECTANGLE)) { - const Region repaint((flags & DisplayHardware::PARTIAL_UPDATES) ? - mDirtyRegion.bounds() : hw.bounds()); - composeSurfaces(repaint); - } - - glDisable(GL_TEXTURE_EXTERNAL_OES); - glDisable(GL_TEXTURE_2D); - glDisable(GL_BLEND); - - static int toggle = 0; - toggle = 1 - toggle; - if (toggle) { - glColor4f(1, 0, 1, 1); - } else { - glColor4f(1, 1, 0, 1); - } - - Region::const_iterator it = mDirtyRegion.begin(); - Region::const_iterator const end = mDirtyRegion.end(); - while (it != end) { - const Rect& r = *it++; - GLfloat vertices[][2] = { - { r.left, height - r.top }, - { r.left, height - r.bottom }, - { r.right, height - r.bottom }, - { r.right, height - r.top } - }; - glVertexPointer(2, GL_FLOAT, 0, vertices); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - } - - hw.flip(mSwapRegion); - - if (mDebugRegion > 1) - usleep(mDebugRegion * 1000); -} - -void SurfaceFlinger::drawWormhole() const +void SurfaceFlinger::drawWormhole(const Region& region) const { - const Region region(mWormholeRegion.intersect(mDirtyRegion)); - if (region.isEmpty()) - return; - glDisable(GL_TEXTURE_EXTERNAL_OES); glDisable(GL_TEXTURE_2D); glDisable(GL_BLEND); @@ -1026,30 +1343,15 @@ void SurfaceFlinger::drawWormhole() const } } -status_t SurfaceFlinger::addLayer(const sp<LayerBase>& layer) -{ - Mutex::Autolock _l(mStateLock); - addLayer_l(layer); - setTransactionFlags(eTransactionNeeded|eTraversalNeeded); - return NO_ERROR; -} - -status_t SurfaceFlinger::addLayer_l(const sp<LayerBase>& layer) -{ - ssize_t i = mCurrentState.layersSortedByZ.add(layer); - return (i < 0) ? status_t(i) : status_t(NO_ERROR); -} - ssize_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<LayerBaseClient>& lbc) { // attach this layer to the client size_t name = client->attachLayer(lbc); - Mutex::Autolock _l(mStateLock); - // add this layer to the current state list - addLayer_l(lbc); + Mutex::Autolock _l(mStateLock); + mCurrentState.layersSortedByZ.add(lbc); return ssize_t(name); } @@ -1065,10 +1367,6 @@ status_t SurfaceFlinger::removeLayer(const sp<LayerBase>& layer) status_t SurfaceFlinger::removeLayer_l(const sp<LayerBase>& layerBase) { - sp<LayerBaseClient> lbc(layerBase->getLayerBaseClient()); - if (lbc != 0) { - mLayerMap.removeItem( lbc->getSurfaceBinder() ); - } ssize_t index = mCurrentState.layersSortedByZ.remove(layerBase); if (index >= 0) { mLayersRemoved = true; @@ -1095,13 +1393,6 @@ status_t SurfaceFlinger::purgatorizeLayer_l(const sp<LayerBase>& layerBase) return (err == NAME_NOT_FOUND) ? status_t(NO_ERROR) : err; } -status_t SurfaceFlinger::invalidateLayerVisibility(const sp<LayerBase>& layer) -{ - layer->forceVisibilityTransaction(); - setTransactionFlags(eTraversalNeeded); - return NO_ERROR; -} - uint32_t SurfaceFlinger::peekTransactionFlags(uint32_t flags) { return android_atomic_release_load(&mTransactionFlags); @@ -1121,23 +1412,21 @@ uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) return old; } - -void SurfaceFlinger::setTransactionState(const Vector<ComposerState>& state, - int orientation, uint32_t flags) { +void SurfaceFlinger::setTransactionState( + const Vector<ComposerState>& state, + const Vector<DisplayState>& displays, + uint32_t flags) +{ Mutex::Autolock _l(mStateLock); - uint32_t transactionFlags = 0; - if (mCurrentState.orientation != orientation) { - if (uint32_t(orientation)<=eOrientation270 || orientation==42) { - mCurrentState.orientation = orientation; - transactionFlags |= eTransactionNeeded; - } else if (orientation != eOrientationUnchanged) { - ALOGW("setTransactionState: ignoring unrecognized orientation: %d", - orientation); - } + + size_t count = displays.size(); + for (size_t i=0 ; i<count ; i++) { + const DisplayState& s(displays[i]); + transactionFlags |= setDisplayStateLocked(s); } - const size_t count = state.size(); + count = state.size(); for (size_t i=0 ; i<count ; i++) { const ComposerState& s(state[i]); sp<Client> client( static_cast<Client *>(s.client.get()) ); @@ -1166,7 +1455,110 @@ void SurfaceFlinger::setTransactionState(const Vector<ComposerState>& state, } } -sp<ISurface> SurfaceFlinger::createSurface( +uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s) +{ + uint32_t flags = 0; + DisplayDeviceState& disp(mCurrentState.displays.editValueFor(s.token)); + if (disp.id >= 0) { + const uint32_t what = s.what; + if (what & DisplayState::eSurfaceChanged) { + if (disp.surface->asBinder() != s.surface->asBinder()) { + disp.surface = s.surface; + flags |= eDisplayTransactionNeeded; + } + } + if (what & DisplayState::eLayerStackChanged) { + if (disp.layerStack != s.layerStack) { + disp.layerStack = s.layerStack; + flags |= eDisplayTransactionNeeded; + } + } + if (what & DisplayState::eOrientationChanged) { + if (disp.orientation != s.orientation) { + disp.orientation = s.orientation; + flags |= eDisplayTransactionNeeded; + } + } + if (what & DisplayState::eFrameChanged) { + if (disp.frame != s.frame) { + disp.frame = s.frame; + flags |= eDisplayTransactionNeeded; + } + } + if (what & DisplayState::eViewportChanged) { + if (disp.viewport != s.viewport) { + disp.viewport = s.viewport; + flags |= eDisplayTransactionNeeded; + } + } + } + return flags; +} + +uint32_t SurfaceFlinger::setClientStateLocked( + const sp<Client>& client, + const layer_state_t& s) +{ + uint32_t flags = 0; + sp<LayerBaseClient> layer(client->getLayerUser(s.surface)); + if (layer != 0) { + const uint32_t what = s.what; + if (what & layer_state_t::ePositionChanged) { + if (layer->setPosition(s.x, s.y)) + flags |= eTraversalNeeded; + } + if (what & layer_state_t::eLayerChanged) { + // NOTE: index needs to be calculated before we update the state + ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); + if (layer->setLayer(s.z)) { + mCurrentState.layersSortedByZ.removeAt(idx); + mCurrentState.layersSortedByZ.add(layer); + // we need traversal (state changed) + // AND transaction (list changed) + flags |= eTransactionNeeded|eTraversalNeeded; + } + } + if (what & layer_state_t::eSizeChanged) { + if (layer->setSize(s.w, s.h)) { + flags |= eTraversalNeeded; + } + } + if (what & layer_state_t::eAlphaChanged) { + if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f))) + flags |= eTraversalNeeded; + } + if (what & layer_state_t::eMatrixChanged) { + if (layer->setMatrix(s.matrix)) + flags |= eTraversalNeeded; + } + if (what & layer_state_t::eTransparentRegionChanged) { + if (layer->setTransparentRegionHint(s.transparentRegion)) + flags |= eTraversalNeeded; + } + if (what & layer_state_t::eVisibilityChanged) { + if (layer->setFlags(s.flags, s.mask)) + flags |= eTraversalNeeded; + } + if (what & layer_state_t::eCropChanged) { + if (layer->setCrop(s.crop)) + flags |= eTraversalNeeded; + } + if (what & layer_state_t::eLayerStackChanged) { + // NOTE: index needs to be calculated before we update the state + ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); + if (layer->setLayerStack(s.layerStack)) { + mCurrentState.layersSortedByZ.removeAt(idx); + mCurrentState.layersSortedByZ.add(layer); + // we need traversal (state changed) + // AND transaction (list changed) + flags |= eTransactionNeeded|eTraversalNeeded; + } + } + } + return flags; +} + +sp<ISurface> SurfaceFlinger::createLayer( ISurfaceComposerClient::surface_data_t* params, const String8& name, const sp<Client>& client, @@ -1177,26 +1569,22 @@ sp<ISurface> SurfaceFlinger::createSurface( sp<ISurface> surfaceHandle; if (int32_t(w|h) < 0) { - ALOGE("createSurface() failed, w or h is negative (w=%d, h=%d)", + ALOGE("createLayer() failed, w or h is negative (w=%d, h=%d)", int(w), int(h)); return surfaceHandle; } - //ALOGD("createSurface for (%d x %d), name=%s", w, h, name.string()); - sp<Layer> normalLayer; - switch (flags & eFXSurfaceMask) { - case eFXSurfaceNormal: - normalLayer = createNormalSurface(client, d, w, h, flags, format); - layer = normalLayer; + //ALOGD("createLayer for (%d x %d), name=%s", w, h, name.string()); + switch (flags & ISurfaceComposerClient::eFXSurfaceMask) { + case ISurfaceComposerClient::eFXSurfaceNormal: + layer = createNormalLayer(client, d, w, h, flags, format); break; - case eFXSurfaceBlur: - // for now we treat Blur as Dim, until we can implement it - // efficiently. - case eFXSurfaceDim: - layer = createDimSurface(client, d, w, h, flags); + case ISurfaceComposerClient::eFXSurfaceBlur: + case ISurfaceComposerClient::eFXSurfaceDim: + layer = createDimLayer(client, d, w, h, flags); break; - case eFXSurfaceScreenshot: - layer = createScreenshotSurface(client, d, w, h, flags); + case ISurfaceComposerClient::eFXSurfaceScreenshot: + layer = createScreenshotLayer(client, d, w, h, flags); break; } @@ -1204,30 +1592,24 @@ sp<ISurface> SurfaceFlinger::createSurface( layer->initStates(w, h, flags); layer->setName(name); ssize_t token = addClientLayer(client, layer); - surfaceHandle = layer->getSurface(); if (surfaceHandle != 0) { params->token = token; params->identity = layer->getIdentity(); - if (normalLayer != 0) { - Mutex::Autolock _l(mStateLock); - mLayerMap.add(layer->getSurfaceBinder(), normalLayer); - } } - setTransactionFlags(eTransactionNeeded); } return surfaceHandle; } -sp<Layer> SurfaceFlinger::createNormalSurface( +sp<Layer> SurfaceFlinger::createNormalLayer( const sp<Client>& client, DisplayID display, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format) { // initialize the surfaces - switch (format) { // TODO: take h/w into account + switch (format) { case PIXEL_FORMAT_TRANSPARENT: case PIXEL_FORMAT_TRANSLUCENT: format = PIXEL_FORMAT_RGBA_8888; @@ -1249,13 +1631,13 @@ sp<Layer> SurfaceFlinger::createNormalSurface( sp<Layer> layer = new Layer(this, display, client); status_t err = layer->setBuffers(w, h, format, flags); if (CC_LIKELY(err != NO_ERROR)) { - ALOGE("createNormalSurfaceLocked() failed (%s)", strerror(-err)); + ALOGE("createNormalLayer() failed (%s)", strerror(-err)); layer.clear(); } return layer; } -sp<LayerDim> SurfaceFlinger::createDimSurface( +sp<LayerDim> SurfaceFlinger::createDimLayer( const sp<Client>& client, DisplayID display, uint32_t w, uint32_t h, uint32_t flags) { @@ -1263,7 +1645,7 @@ sp<LayerDim> SurfaceFlinger::createDimSurface( return layer; } -sp<LayerScreenshot> SurfaceFlinger::createScreenshotSurface( +sp<LayerScreenshot> SurfaceFlinger::createScreenshotLayer( const sp<Client>& client, DisplayID display, uint32_t w, uint32_t h, uint32_t flags) { @@ -1271,7 +1653,7 @@ sp<LayerScreenshot> SurfaceFlinger::createScreenshotSurface( return layer; } -status_t SurfaceFlinger::removeSurface(const sp<Client>& client, SurfaceID sid) +status_t SurfaceFlinger::onLayerRemoved(const sp<Client>& client, SurfaceID sid) { /* * called by the window manager, when a surface should be marked for @@ -1295,7 +1677,7 @@ status_t SurfaceFlinger::removeSurface(const sp<Client>& client, SurfaceID sid) return err; } -status_t SurfaceFlinger::destroySurface(const wp<LayerBaseClient>& layer) +status_t SurfaceFlinger::onLayerDestroyed(const wp<LayerBaseClient>& layer) { // called by ~ISurface() when all references are gone status_t err = NO_ERROR; @@ -1317,80 +1699,30 @@ status_t SurfaceFlinger::destroySurface(const wp<LayerBaseClient>& layer) return err; } -uint32_t SurfaceFlinger::setClientStateLocked( - const sp<Client>& client, - const layer_state_t& s) -{ - uint32_t flags = 0; - sp<LayerBaseClient> layer(client->getLayerUser(s.surface)); - if (layer != 0) { - const uint32_t what = s.what; - if (what & ePositionChanged) { - if (layer->setPosition(s.x, s.y)) - flags |= eTraversalNeeded; - } - if (what & eLayerChanged) { - ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); - if (layer->setLayer(s.z)) { - mCurrentState.layersSortedByZ.removeAt(idx); - mCurrentState.layersSortedByZ.add(layer); - // we need traversal (state changed) - // AND transaction (list changed) - flags |= eTransactionNeeded|eTraversalNeeded; - } - } - if (what & eSizeChanged) { - if (layer->setSize(s.w, s.h)) { - flags |= eTraversalNeeded; - } - } - if (what & eAlphaChanged) { - if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f))) - flags |= eTraversalNeeded; - } - if (what & eMatrixChanged) { - if (layer->setMatrix(s.matrix)) - flags |= eTraversalNeeded; - } - if (what & eTransparentRegionChanged) { - if (layer->setTransparentRegionHint(s.transparentRegion)) - flags |= eTraversalNeeded; - } - if (what & eVisibilityChanged) { - if (layer->setFlags(s.flags, s.mask)) - flags |= eTraversalNeeded; - } - if (what & eCropChanged) { - if (layer->setCrop(s.crop)) - flags |= eTraversalNeeded; - } - } - return flags; -} - // --------------------------------------------------------------------------- void SurfaceFlinger::onScreenAcquired() { - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - hw.acquireScreen(); + ALOGD("Screen about to return, flinger = %p", this); + sp<const DisplayDevice> hw(getDefaultDisplayDevice()); // XXX: this should be per DisplayDevice + getHwComposer().acquire(); + hw->acquireScreen(); mEventThread->onScreenAcquired(); - // this is a temporary work-around, eventually this should be called - // by the power-manager - SurfaceFlinger::turnElectronBeamOn(mElectronBeamAnimationMode); - // from this point on, SF will process updates again + mVisibleRegionsDirty = true; repaintEverything(); } void SurfaceFlinger::onScreenReleased() { - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - if (hw.isScreenAcquired()) { + ALOGD("About to give-up screen, flinger = %p", this); + sp<const DisplayDevice> hw(getDefaultDisplayDevice()); // XXX: this should be per DisplayDevice + if (hw->isScreenAcquired()) { mEventThread->onScreenReleased(); - hw.releaseScreen(); + hw->releaseScreen(); + getHwComposer().release(); // from this point on, SF will stop drawing } } -void SurfaceFlinger::screenAcquired() { +void SurfaceFlinger::unblank() { class MessageScreenAcquired : public MessageBase { SurfaceFlinger* flinger; public: @@ -1404,7 +1736,7 @@ void SurfaceFlinger::screenAcquired() { postMessageSync(msg); } -void SurfaceFlinger::screenReleased() { +void SurfaceFlinger::blank() { class MessageScreenReleased : public MessageBase { SurfaceFlinger* flinger; public: @@ -1575,12 +1907,34 @@ void SurfaceFlinger::dumpAllLocked( } /* + * Dump Display state + */ + + for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { + const sp<const DisplayDevice>& hw(mDisplays[dpy]); + snprintf(buffer, SIZE, + "+ DisplayDevice[%u]\n" + " id=%x, layerStack=%u, (%4dx%4d), orient=%2d, tr=%08x, " + "flips=%u, secure=%d, numLayers=%u\n", + dpy, + hw->getDisplayId(), hw->getLayerStack(), + hw->getWidth(), hw->getHeight(), + hw->getOrientation(), hw->getTransform().getType(), + hw->getPageFlipCount(), + hw->getSecureLayerVisible(), + hw->getVisibleLayersSortedByZ().size()); + result.append(buffer); + } + + /* * Dump SurfaceFlinger global state */ snprintf(buffer, SIZE, "SurfaceFlinger global state:\n"); result.append(buffer); + HWComposer& hwc(getHwComposer()); + sp<const DisplayDevice> hw(getDefaultDisplayDevice()); const GLExtensions& extensions(GLExtensions::getInstance()); snprintf(buffer, SIZE, "GLES: %s, %s, %s\n", extensions.getVendor(), @@ -1589,18 +1943,16 @@ void SurfaceFlinger::dumpAllLocked( result.append(buffer); snprintf(buffer, SIZE, "EGL : %s\n", - eglQueryString(graphicPlane(0).getEGLDisplay(), - EGL_VERSION_HW_ANDROID)); + eglQueryString(mEGLDisplay, EGL_VERSION_HW_ANDROID)); result.append(buffer); snprintf(buffer, SIZE, "EXTS: %s\n", extensions.getExtension()); result.append(buffer); - mWormholeRegion.dump(result, "WormholeRegion"); - const DisplayHardware& hw(graphicPlane(0).displayHardware()); + hw->undefinedRegion.dump(result, "undefinedRegion"); snprintf(buffer, SIZE, " orientation=%d, canDraw=%d\n", - mCurrentState.orientation, hw.canDraw()); + hw->getOrientation(), hw->canDraw()); result.append(buffer); snprintf(buffer, SIZE, " last eglSwapBuffers() time: %f us\n" @@ -1608,15 +1960,13 @@ void SurfaceFlinger::dumpAllLocked( " transaction-flags : %08x\n" " refresh-rate : %f fps\n" " x-dpi : %f\n" - " y-dpi : %f\n" - " density : %f\n", + " y-dpi : %f\n", mLastSwapBufferTime/1000.0, mLastTransactionTime/1000.0, mTransactionFlags, - hw.getRefreshRate(), - hw.getDpiX(), - hw.getDpiY(), - hw.getDensity()); + 1e9 / hwc.getRefreshPeriod(), + hwc.getDpiX(), + hwc.getDpiY()); result.append(buffer); snprintf(buffer, SIZE, " eglSwapBuffers time: %f us\n", @@ -1635,21 +1985,20 @@ void SurfaceFlinger::dumpAllLocked( /* * Dump HWComposer state */ - HWComposer& hwc(hw.getHwComposer()); snprintf(buffer, SIZE, "h/w composer state:\n"); result.append(buffer); snprintf(buffer, SIZE, " h/w composer %s and %s\n", hwc.initCheck()==NO_ERROR ? "present" : "not present", (mDebugDisableHWC || mDebugRegion) ? "disabled" : "enabled"); result.append(buffer); - hwc.dump(result, buffer, SIZE, mVisibleLayersSortedByZ); + hwc.dump(result, buffer, SIZE, hw->getVisibleLayersSortedByZ()); /* * Dump gralloc state */ const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get()); alloc.dump(result); - hw.dump(result); + hw->dump(result); } status_t SurfaceFlinger::onTransact( @@ -1658,10 +2007,9 @@ status_t SurfaceFlinger::onTransact( switch (code) { case CREATE_CONNECTION: case SET_TRANSACTION_STATE: - case SET_ORIENTATION: case BOOT_FINISHED: - case TURN_ELECTRON_BEAM_OFF: - case TURN_ELECTRON_BEAM_ON: + case BLANK: + case UNBLANK: { // codes that require permission check IPCThreadState* ipc = IPCThreadState::self(); @@ -1718,7 +2066,10 @@ status_t SurfaceFlinger::onTransact( return NO_ERROR; } case 1005:{ // force transaction - setTransactionFlags(eTransactionNeeded|eTraversalNeeded); + setTransactionFlags( + eTransactionNeeded| + eDisplayTransactionNeeded| + eTraversalNeeded); return NO_ERROR; } case 1006:{ // send empty update @@ -1746,8 +2097,8 @@ status_t SurfaceFlinger::onTransact( return NO_ERROR; case 1013: { Mutex::Autolock _l(mStateLock); - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - reply->writeInt32(hw.getPageFlipCount()); + sp<const DisplayDevice> hw(getDefaultDisplayDevice()); + reply->writeInt32(hw->getPageFlipCount()); } return NO_ERROR; } @@ -1756,24 +2107,10 @@ status_t SurfaceFlinger::onTransact( } void SurfaceFlinger::repaintEverything() { - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - const Rect bounds(hw.getBounds()); - setInvalidateRegion(Region(bounds)); + android_atomic_or(1, &mRepaintEverything); signalTransaction(); } -void SurfaceFlinger::setInvalidateRegion(const Region& reg) { - Mutex::Autolock _l(mInvalidateLock); - mInvalidateRegion = reg; -} - -Region SurfaceFlinger::getAndClearInvalidateRegion() { - Mutex::Autolock _l(mInvalidateLock); - Region reg(mInvalidateRegion); - mInvalidateRegion.clear(); - return reg; -} - // --------------------------------------------------------------------------- status_t SurfaceFlinger::renderScreenToTexture(DisplayID dpy, @@ -1792,9 +2129,9 @@ status_t SurfaceFlinger::renderScreenToTextureLocked(DisplayID dpy, return INVALID_OPERATION; // get screen geometry - const DisplayHardware& hw(graphicPlane(dpy).displayHardware()); - const uint32_t hw_w = hw.getWidth(); - const uint32_t hw_h = hw.getHeight(); + sp<const DisplayDevice> hw(getDisplayDevice(dpy)); + const uint32_t hw_w = hw->getWidth(); + const uint32_t hw_h = hw->getHeight(); GLfloat u = 1; GLfloat v = 1; @@ -1830,14 +2167,14 @@ status_t SurfaceFlinger::renderScreenToTextureLocked(DisplayID dpy, glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); - const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ); + const Vector< sp<LayerBase> >& layers(hw->getVisibleLayersSortedByZ()); const size_t count = layers.size(); for (size_t i=0 ; i<count ; ++i) { const sp<LayerBase>& layer(layers[i]); - layer->drawForSreenShot(); + layer->draw(hw); } - hw.compositionComplete(); + hw->compositionComplete(); // back to main framebuffer glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); @@ -1851,471 +2188,6 @@ status_t SurfaceFlinger::renderScreenToTextureLocked(DisplayID dpy, // --------------------------------------------------------------------------- -class VSyncWaiter { - DisplayEventReceiver::Event buffer[4]; - sp<Looper> looper; - sp<IDisplayEventConnection> events; - sp<BitTube> eventTube; -public: - VSyncWaiter(const sp<EventThread>& eventThread) { - looper = new Looper(true); - events = eventThread->createEventConnection(); - eventTube = events->getDataChannel(); - looper->addFd(eventTube->getFd(), 0, ALOOPER_EVENT_INPUT, 0, 0); - events->requestNextVsync(); - } - - void wait() { - ssize_t n; - - looper->pollOnce(-1); - // we don't handle any errors here, it doesn't matter - // and we don't want to take the risk to get stuck. - - // drain the events... - while ((n = DisplayEventReceiver::getEvents( - eventTube, buffer, 4)) > 0) ; - - events->requestNextVsync(); - } -}; - -status_t SurfaceFlinger::electronBeamOffAnimationImplLocked() -{ - // get screen geometry - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - const uint32_t hw_w = hw.getWidth(); - const uint32_t hw_h = hw.getHeight(); - const Region screenBounds(hw.getBounds()); - - GLfloat u, v; - GLuint tname; - status_t result = renderScreenToTextureLocked(0, &tname, &u, &v); - if (result != NO_ERROR) { - return result; - } - - GLfloat vtx[8]; - const GLfloat texCoords[4][2] = { {0,0}, {0,v}, {u,v}, {u,0} }; - glBindTexture(GL_TEXTURE_2D, tname); - glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexCoordPointer(2, GL_FLOAT, 0, texCoords); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glVertexPointer(2, GL_FLOAT, 0, vtx); - - /* - * Texture coordinate mapping - * - * u - * 1 +----------+---+ - * | | | | image is inverted - * | V | | w.r.t. the texture - * 1-v +----------+ | coordinates - * | | - * | | - * | | - * 0 +--------------+ - * 0 1 - * - */ - - class s_curve_interpolator { - const float nbFrames, s, v; - public: - s_curve_interpolator(int nbFrames, float s) - : nbFrames(1.0f / (nbFrames-1)), s(s), - v(1.0f + expf(-s + 0.5f*s)) { - } - float operator()(int f) { - const float x = f * nbFrames; - return ((1.0f/(1.0f + expf(-x*s + 0.5f*s))) - 0.5f) * v + 0.5f; - } - }; - - class v_stretch { - const GLfloat hw_w, hw_h; - public: - v_stretch(uint32_t hw_w, uint32_t hw_h) - : hw_w(hw_w), hw_h(hw_h) { - } - void operator()(GLfloat* vtx, float v) { - const GLfloat w = hw_w + (hw_w * v); - const GLfloat h = hw_h - (hw_h * v); - const GLfloat x = (hw_w - w) * 0.5f; - const GLfloat y = (hw_h - h) * 0.5f; - vtx[0] = x; vtx[1] = y; - vtx[2] = x; vtx[3] = y + h; - vtx[4] = x + w; vtx[5] = y + h; - vtx[6] = x + w; vtx[7] = y; - } - }; - - class h_stretch { - const GLfloat hw_w, hw_h; - public: - h_stretch(uint32_t hw_w, uint32_t hw_h) - : hw_w(hw_w), hw_h(hw_h) { - } - void operator()(GLfloat* vtx, float v) { - const GLfloat w = hw_w - (hw_w * v); - const GLfloat h = 1.0f; - const GLfloat x = (hw_w - w) * 0.5f; - const GLfloat y = (hw_h - h) * 0.5f; - vtx[0] = x; vtx[1] = y; - vtx[2] = x; vtx[3] = y + h; - vtx[4] = x + w; vtx[5] = y + h; - vtx[6] = x + w; vtx[7] = y; - } - }; - - VSyncWaiter vsync(mEventThread); - - // the full animation is 24 frames - char value[PROPERTY_VALUE_MAX]; - property_get("debug.sf.electron_frames", value, "24"); - int nbFrames = (atoi(value) + 1) >> 1; - if (nbFrames <= 0) // just in case - nbFrames = 24; - - s_curve_interpolator itr(nbFrames, 7.5f); - s_curve_interpolator itg(nbFrames, 8.0f); - s_curve_interpolator itb(nbFrames, 8.5f); - - v_stretch vverts(hw_w, hw_h); - - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE); - for (int i=0 ; i<nbFrames ; i++) { - float x, y, w, h; - const float vr = itr(i); - const float vg = itg(i); - const float vb = itb(i); - - // wait for vsync - vsync.wait(); - - // clear screen - glColorMask(1,1,1,1); - glClear(GL_COLOR_BUFFER_BIT); - glEnable(GL_TEXTURE_2D); - - // draw the red plane - vverts(vtx, vr); - glColorMask(1,0,0,1); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - // draw the green plane - vverts(vtx, vg); - glColorMask(0,1,0,1); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - // draw the blue plane - vverts(vtx, vb); - glColorMask(0,0,1,1); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - // draw the white highlight (we use the last vertices) - glDisable(GL_TEXTURE_2D); - glColorMask(1,1,1,1); - glColor4f(vg, vg, vg, 1); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - hw.flip(screenBounds); - } - - h_stretch hverts(hw_w, hw_h); - glDisable(GL_BLEND); - glDisable(GL_TEXTURE_2D); - glColorMask(1,1,1,1); - for (int i=0 ; i<nbFrames ; i++) { - const float v = itg(i); - hverts(vtx, v); - - // wait for vsync - vsync.wait(); - - glClear(GL_COLOR_BUFFER_BIT); - glColor4f(1-v, 1-v, 1-v, 1); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - hw.flip(screenBounds); - } - - glColorMask(1,1,1,1); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDeleteTextures(1, &tname); - glDisable(GL_TEXTURE_2D); - glDisable(GL_BLEND); - return NO_ERROR; -} - -status_t SurfaceFlinger::electronBeamOnAnimationImplLocked() -{ - status_t result = PERMISSION_DENIED; - - if (!GLExtensions::getInstance().haveFramebufferObject()) - return INVALID_OPERATION; - - - // get screen geometry - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - const uint32_t hw_w = hw.getWidth(); - const uint32_t hw_h = hw.getHeight(); - const Region screenBounds(hw.bounds()); - - GLfloat u, v; - GLuint tname; - result = renderScreenToTextureLocked(0, &tname, &u, &v); - if (result != NO_ERROR) { - return result; - } - - GLfloat vtx[8]; - const GLfloat texCoords[4][2] = { {0,v}, {0,0}, {u,0}, {u,v} }; - glBindTexture(GL_TEXTURE_2D, tname); - glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexCoordPointer(2, GL_FLOAT, 0, texCoords); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glVertexPointer(2, GL_FLOAT, 0, vtx); - - class s_curve_interpolator { - const float nbFrames, s, v; - public: - s_curve_interpolator(int nbFrames, float s) - : nbFrames(1.0f / (nbFrames-1)), s(s), - v(1.0f + expf(-s + 0.5f*s)) { - } - float operator()(int f) { - const float x = f * nbFrames; - return ((1.0f/(1.0f + expf(-x*s + 0.5f*s))) - 0.5f) * v + 0.5f; - } - }; - - class v_stretch { - const GLfloat hw_w, hw_h; - public: - v_stretch(uint32_t hw_w, uint32_t hw_h) - : hw_w(hw_w), hw_h(hw_h) { - } - void operator()(GLfloat* vtx, float v) { - const GLfloat w = hw_w + (hw_w * v); - const GLfloat h = hw_h - (hw_h * v); - const GLfloat x = (hw_w - w) * 0.5f; - const GLfloat y = (hw_h - h) * 0.5f; - vtx[0] = x; vtx[1] = y; - vtx[2] = x; vtx[3] = y + h; - vtx[4] = x + w; vtx[5] = y + h; - vtx[6] = x + w; vtx[7] = y; - } - }; - - class h_stretch { - const GLfloat hw_w, hw_h; - public: - h_stretch(uint32_t hw_w, uint32_t hw_h) - : hw_w(hw_w), hw_h(hw_h) { - } - void operator()(GLfloat* vtx, float v) { - const GLfloat w = hw_w - (hw_w * v); - const GLfloat h = 1.0f; - const GLfloat x = (hw_w - w) * 0.5f; - const GLfloat y = (hw_h - h) * 0.5f; - vtx[0] = x; vtx[1] = y; - vtx[2] = x; vtx[3] = y + h; - vtx[4] = x + w; vtx[5] = y + h; - vtx[6] = x + w; vtx[7] = y; - } - }; - - VSyncWaiter vsync(mEventThread); - - // the full animation is 12 frames - int nbFrames = 8; - s_curve_interpolator itr(nbFrames, 7.5f); - s_curve_interpolator itg(nbFrames, 8.0f); - s_curve_interpolator itb(nbFrames, 8.5f); - - h_stretch hverts(hw_w, hw_h); - glDisable(GL_BLEND); - glDisable(GL_TEXTURE_2D); - glColorMask(1,1,1,1); - for (int i=nbFrames-1 ; i>=0 ; i--) { - const float v = itg(i); - hverts(vtx, v); - - // wait for vsync - vsync.wait(); - - glClear(GL_COLOR_BUFFER_BIT); - glColor4f(1-v, 1-v, 1-v, 1); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - hw.flip(screenBounds); - } - - nbFrames = 4; - v_stretch vverts(hw_w, hw_h); - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE); - for (int i=nbFrames-1 ; i>=0 ; i--) { - float x, y, w, h; - const float vr = itr(i); - const float vg = itg(i); - const float vb = itb(i); - - // wait for vsync - vsync.wait(); - - // clear screen - glColorMask(1,1,1,1); - glClear(GL_COLOR_BUFFER_BIT); - glEnable(GL_TEXTURE_2D); - - // draw the red plane - vverts(vtx, vr); - glColorMask(1,0,0,1); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - // draw the green plane - vverts(vtx, vg); - glColorMask(0,1,0,1); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - // draw the blue plane - vverts(vtx, vb); - glColorMask(0,0,1,1); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - hw.flip(screenBounds); - } - - glColorMask(1,1,1,1); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDeleteTextures(1, &tname); - glDisable(GL_TEXTURE_2D); - glDisable(GL_BLEND); - - return NO_ERROR; -} - -// --------------------------------------------------------------------------- - -status_t SurfaceFlinger::turnElectronBeamOffImplLocked(int32_t mode) -{ - ATRACE_CALL(); - - DisplayHardware& hw(graphicPlane(0).editDisplayHardware()); - if (!hw.canDraw()) { - // we're already off - return NO_ERROR; - } - - // turn off hwc while we're doing the animation - hw.getHwComposer().disable(); - // and make sure to turn it back on (if needed) next time we compose - invalidateHwcGeometry(); - - if (mode & ISurfaceComposer::eElectronBeamAnimationOff) { - electronBeamOffAnimationImplLocked(); - } - - // always clear the whole screen at the end of the animation - glClearColor(0,0,0,1); - glClear(GL_COLOR_BUFFER_BIT); - hw.flip( Region(hw.bounds()) ); - - return NO_ERROR; -} - -status_t SurfaceFlinger::turnElectronBeamOff(int32_t mode) -{ - class MessageTurnElectronBeamOff : public MessageBase { - SurfaceFlinger* flinger; - int32_t mode; - status_t result; - public: - MessageTurnElectronBeamOff(SurfaceFlinger* flinger, int32_t mode) - : flinger(flinger), mode(mode), result(PERMISSION_DENIED) { - } - status_t getResult() const { - return result; - } - virtual bool handler() { - Mutex::Autolock _l(flinger->mStateLock); - result = flinger->turnElectronBeamOffImplLocked(mode); - return true; - } - }; - - sp<MessageBase> msg = new MessageTurnElectronBeamOff(this, mode); - status_t res = postMessageSync(msg); - if (res == NO_ERROR) { - res = static_cast<MessageTurnElectronBeamOff*>( msg.get() )->getResult(); - - // work-around: when the power-manager calls us we activate the - // animation. eventually, the "on" animation will be called - // by the power-manager itself - mElectronBeamAnimationMode = mode; - } - return res; -} - -// --------------------------------------------------------------------------- - -status_t SurfaceFlinger::turnElectronBeamOnImplLocked(int32_t mode) -{ - DisplayHardware& hw(graphicPlane(0).editDisplayHardware()); - if (hw.canDraw()) { - // we're already on - return NO_ERROR; - } - if (mode & ISurfaceComposer::eElectronBeamAnimationOn) { - electronBeamOnAnimationImplLocked(); - } - - // make sure to redraw the whole screen when the animation is done - mDirtyRegion.set(hw.bounds()); - signalTransaction(); - - return NO_ERROR; -} - -status_t SurfaceFlinger::turnElectronBeamOn(int32_t mode) -{ - class MessageTurnElectronBeamOn : public MessageBase { - SurfaceFlinger* flinger; - int32_t mode; - status_t result; - public: - MessageTurnElectronBeamOn(SurfaceFlinger* flinger, int32_t mode) - : flinger(flinger), mode(mode), result(PERMISSION_DENIED) { - } - status_t getResult() const { - return result; - } - virtual bool handler() { - Mutex::Autolock _l(flinger->mStateLock); - result = flinger->turnElectronBeamOnImplLocked(mode); - return true; - } - }; - - postMessageAsync( new MessageTurnElectronBeamOn(this, mode) ); - return NO_ERROR; -} - -// --------------------------------------------------------------------------- - status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy, sp<IMemoryHeap>* heap, uint32_t* w, uint32_t* h, PixelFormat* f, @@ -2327,26 +2199,38 @@ status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy, status_t result = PERMISSION_DENIED; // only one display supported for now - if (CC_UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT)) + if (CC_UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT)) { + ALOGE("invalid display %d", dpy); return BAD_VALUE; + } - if (!GLExtensions::getInstance().haveFramebufferObject()) + if (!GLExtensions::getInstance().haveFramebufferObject()) { return INVALID_OPERATION; + } // get screen geometry - const DisplayHardware& hw(graphicPlane(dpy).displayHardware()); - const uint32_t hw_w = hw.getWidth(); - const uint32_t hw_h = hw.getHeight(); + sp<const DisplayDevice> hw(getDisplayDevice(dpy)); + const uint32_t hw_w = hw->getWidth(); + const uint32_t hw_h = hw->getHeight(); + + // if we have secure windows on this display, never allow the screen capture + if (hw->getSecureLayerVisible()) { + ALOGW("FB is protected: PERMISSION_DENIED"); + return PERMISSION_DENIED; + } - if ((sw > hw_w) || (sh > hw_h)) + if ((sw > hw_w) || (sh > hw_h)) { + ALOGE("size mismatch (%d, %d) > (%d, %d)", sw, sh, hw_w, hw_h); return BAD_VALUE; + } sw = (!sw) ? hw_w : sw; sh = (!sh) ? hw_h : sh; const size_t size = sw * sh * 4; + const bool filtering = sw != hw_w || sh != hw_h; - //ALOGD("screenshot: sw=%d, sh=%d, minZ=%d, maxZ=%d", - // sw, sh, minLayerZ, maxLayerZ); +// ALOGD("screenshot: sw=%d, sh=%d, minZ=%d, maxZ=%d", +// sw, sh, minLayerZ, maxLayerZ); // make sure to clear all GL error flags while ( glGetError() != GL_NO_ERROR ) ; @@ -2383,10 +2267,12 @@ status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy, for (size_t i=0 ; i<count ; ++i) { const sp<LayerBase>& layer(layers[i]); const uint32_t flags = layer->drawingState().flags; - if (!(flags & ISurfaceComposer::eLayerHidden)) { + if (!(flags & layer_state_t::eLayerHidden)) { const uint32_t z = layer->drawingState().z; if (z >= minLayerZ && z <= maxLayerZ) { - layer->drawForSreenShot(); + if (filtering) layer->setFiltering(true); + layer->draw(hw); + if (filtering) layer->setFiltering(false); } } } @@ -2429,9 +2315,9 @@ status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy, glDeleteRenderbuffersOES(1, &tname); glDeleteFramebuffersOES(1, &name); - hw.compositionComplete(); + hw->compositionComplete(); - // ALOGD("screenshot: result = %s", result<0 ? strerror(result) : "OK"); +// ALOGD("screenshot: result = %s", result<0 ? strerror(result) : "OK"); return result; } @@ -2478,14 +2364,8 @@ status_t SurfaceFlinger::captureScreen(DisplayID dpy, } virtual bool handler() { Mutex::Autolock _l(flinger->mStateLock); - - // if we have secure windows, never allow the screen capture - if (flinger->mSecureFrameBuffer) - return true; - result = flinger->captureScreenImplLocked(dpy, heap, w, h, f, sw, sh, minLayerZ, maxLayerZ); - return true; } }; @@ -2501,136 +2381,40 @@ status_t SurfaceFlinger::captureScreen(DisplayID dpy, // --------------------------------------------------------------------------- -sp<Layer> SurfaceFlinger::getLayer(const sp<ISurface>& sur) const -{ - sp<Layer> result; - Mutex::Autolock _l(mStateLock); - result = mLayerMap.valueFor( sur->asBinder() ).promote(); - return result; +SurfaceFlinger::LayerVector::LayerVector() { } -// --------------------------------------------------------------------------- - -Client::Client(const sp<SurfaceFlinger>& flinger) - : mFlinger(flinger), mNameGenerator(1) -{ +SurfaceFlinger::LayerVector::LayerVector(const LayerVector& rhs) + : SortedVector<sp<LayerBase> >(rhs) { } -Client::~Client() +int SurfaceFlinger::LayerVector::do_compare(const void* lhs, + const void* rhs) const { - const size_t count = mLayers.size(); - for (size_t i=0 ; i<count ; i++) { - sp<LayerBaseClient> layer(mLayers.valueAt(i).promote()); - if (layer != 0) { - mFlinger->removeLayer(layer); - } - } -} + // sort layers per layer-stack, then by z-order and finally by sequence + const sp<LayerBase>& l(*reinterpret_cast<const sp<LayerBase>*>(lhs)); + const sp<LayerBase>& r(*reinterpret_cast<const sp<LayerBase>*>(rhs)); -status_t Client::initCheck() const { - return NO_ERROR; -} + uint32_t ls = l->currentState().layerStack; + uint32_t rs = r->currentState().layerStack; + if (ls != rs) + return ls - rs; -size_t Client::attachLayer(const sp<LayerBaseClient>& layer) -{ - Mutex::Autolock _l(mLock); - size_t name = mNameGenerator++; - mLayers.add(name, layer); - return name; -} + uint32_t lz = l->currentState().z; + uint32_t rz = r->currentState().z; + if (lz != rz) + return lz - rz; -void Client::detachLayer(const LayerBaseClient* layer) -{ - Mutex::Autolock _l(mLock); - // we do a linear search here, because this doesn't happen often - const size_t count = mLayers.size(); - for (size_t i=0 ; i<count ; i++) { - if (mLayers.valueAt(i) == layer) { - mLayers.removeItemsAt(i, 1); - break; - } - } -} -sp<LayerBaseClient> Client::getLayerUser(int32_t i) const -{ - Mutex::Autolock _l(mLock); - sp<LayerBaseClient> lbc; - wp<LayerBaseClient> layer(mLayers.valueFor(i)); - if (layer != 0) { - lbc = layer.promote(); - ALOGE_IF(lbc==0, "getLayerUser(name=%d) is dead", int(i)); - } - return lbc; + return l->sequence - r->sequence; } +// --------------------------------------------------------------------------- -status_t Client::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - // these must be checked - IPCThreadState* ipc = IPCThreadState::self(); - const int pid = ipc->getCallingPid(); - const int uid = ipc->getCallingUid(); - const int self_pid = getpid(); - if (CC_UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != 0)) { - // we're called from a different process, do the real check - if (!PermissionCache::checkCallingPermission(sAccessSurfaceFlinger)) - { - ALOGE("Permission Denial: " - "can't openGlobalTransaction pid=%d, uid=%d", pid, uid); - return PERMISSION_DENIED; - } - } - return BnSurfaceComposerClient::onTransact(code, data, reply, flags); +SurfaceFlinger::DisplayDeviceState::DisplayDeviceState() : id(-1) { } - -sp<ISurface> Client::createSurface( - ISurfaceComposerClient::surface_data_t* params, - const String8& name, - DisplayID display, uint32_t w, uint32_t h, PixelFormat format, - uint32_t flags) -{ - /* - * createSurface must be called from the GL thread so that it can - * have access to the GL context. - */ - - class MessageCreateSurface : public MessageBase { - sp<ISurface> result; - SurfaceFlinger* flinger; - ISurfaceComposerClient::surface_data_t* params; - Client* client; - const String8& name; - DisplayID display; - uint32_t w, h; - PixelFormat format; - uint32_t flags; - public: - MessageCreateSurface(SurfaceFlinger* flinger, - ISurfaceComposerClient::surface_data_t* params, - const String8& name, Client* client, - DisplayID display, uint32_t w, uint32_t h, PixelFormat format, - uint32_t flags) - : flinger(flinger), params(params), client(client), name(name), - display(display), w(w), h(h), format(format), flags(flags) - { - } - sp<ISurface> getResult() const { return result; } - virtual bool handler() { - result = flinger->createSurface(params, name, client, - display, w, h, format, flags); - return true; - } - }; - - sp<MessageBase> msg = new MessageCreateSurface(mFlinger.get(), - params, name, this, display, w, h, format, flags); - mFlinger->postMessageSync(msg); - return static_cast<MessageCreateSurface*>( msg.get() )->getResult(); -} -status_t Client::destroySurface(SurfaceID sid) { - return mFlinger->removeSurface(this, sid); +SurfaceFlinger::DisplayDeviceState::DisplayDeviceState(int32_t id) + : id(id), layerStack(0), orientation(0) { } // --------------------------------------------------------------------------- @@ -2658,126 +2442,4 @@ sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h // --------------------------------------------------------------------------- -GraphicPlane::GraphicPlane() - : mHw(0) -{ -} - -GraphicPlane::~GraphicPlane() { - delete mHw; -} - -bool GraphicPlane::initialized() const { - return mHw ? true : false; -} - -int GraphicPlane::getWidth() const { - return mWidth; -} - -int GraphicPlane::getHeight() const { - return mHeight; -} - -void GraphicPlane::setDisplayHardware(DisplayHardware *hw) -{ - mHw = hw; - - // initialize the display orientation transform. - // it's a constant that should come from the display driver. - int displayOrientation = ISurfaceComposer::eOrientationDefault; - char property[PROPERTY_VALUE_MAX]; - if (property_get("ro.sf.hwrotation", property, NULL) > 0) { - //displayOrientation - switch (atoi(property)) { - case 90: - displayOrientation = ISurfaceComposer::eOrientation90; - break; - case 270: - displayOrientation = ISurfaceComposer::eOrientation270; - break; - } - } - - const float w = hw->getWidth(); - const float h = hw->getHeight(); - GraphicPlane::orientationToTransfrom(displayOrientation, w, h, - &mDisplayTransform); - if (displayOrientation & ISurfaceComposer::eOrientationSwapMask) { - mDisplayWidth = h; - mDisplayHeight = w; - } else { - mDisplayWidth = w; - mDisplayHeight = h; - } - - setOrientation(ISurfaceComposer::eOrientationDefault); -} - -status_t GraphicPlane::orientationToTransfrom( - int orientation, int w, int h, Transform* tr) -{ - uint32_t flags = 0; - switch (orientation) { - case ISurfaceComposer::eOrientationDefault: - flags = Transform::ROT_0; - break; - case ISurfaceComposer::eOrientation90: - flags = Transform::ROT_90; - break; - case ISurfaceComposer::eOrientation180: - flags = Transform::ROT_180; - break; - case ISurfaceComposer::eOrientation270: - flags = Transform::ROT_270; - break; - default: - return BAD_VALUE; - } - tr->set(flags, w, h); - return NO_ERROR; -} - -status_t GraphicPlane::setOrientation(int orientation) -{ - // If the rotation can be handled in hardware, this is where - // the magic should happen. - - const DisplayHardware& hw(displayHardware()); - const float w = mDisplayWidth; - const float h = mDisplayHeight; - mWidth = int(w); - mHeight = int(h); - - Transform orientationTransform; - GraphicPlane::orientationToTransfrom(orientation, w, h, - &orientationTransform); - if (orientation & ISurfaceComposer::eOrientationSwapMask) { - mWidth = int(h); - mHeight = int(w); - } - - mOrientation = orientation; - mGlobalTransform = mDisplayTransform * orientationTransform; - return NO_ERROR; -} - -const DisplayHardware& GraphicPlane::displayHardware() const { - return *mHw; -} - -DisplayHardware& GraphicPlane::editDisplayHardware() { - return *mHw; -} - -const Transform& GraphicPlane::transform() const { - return mGlobalTransform; -} - -EGLDisplay GraphicPlane::getEGLDisplay() const { - return mHw->getEGLDisplay(); -} - -// --------------------------------------------------------------------------- - }; // namespace android diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index b20973b..1f79906 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -20,6 +20,9 @@ #include <stdint.h> #include <sys/types.h> +#include <EGL/egl.h> +#include <GLES/gl.h> + #include <cutils/compiler.h> #include <utils/Atomic.h> @@ -33,66 +36,38 @@ #include <binder/IMemory.h> #include <ui/PixelFormat.h> + #include <gui/IGraphicBufferAlloc.h> #include <gui/ISurfaceComposer.h> #include <gui/ISurfaceComposerClient.h> -#include "Barrier.h" -#include "Layer.h" +#include <hardware/hwcomposer_defs.h> + +#include <private/gui/LayerState.h> +#include "Barrier.h" #include "MessageQueue.h" +#include "DisplayDevice.h" + +#include "DisplayHardware/HWComposer.h" namespace android { // --------------------------------------------------------------------------- class Client; -class DisplayHardware; class DisplayEventConnection; class EventThread; class Layer; +class LayerBase; +class LayerBaseClient; class LayerDim; class LayerScreenshot; -struct surface_flinger_cblk_t; +class SurfaceTextureClient; // --------------------------------------------------------------------------- -class Client : public BnSurfaceComposerClient -{ -public: - Client(const sp<SurfaceFlinger>& flinger); - ~Client(); - - status_t initCheck() const; - - // protected by SurfaceFlinger::mStateLock - size_t attachLayer(const sp<LayerBaseClient>& layer); - void detachLayer(const LayerBaseClient* layer); - sp<LayerBaseClient> getLayerUser(int32_t i) const; - -private: - // ISurfaceComposerClient interface - virtual sp<ISurface> createSurface( - surface_data_t* params, const String8& name, - DisplayID display, uint32_t w, uint32_t h,PixelFormat format, - uint32_t flags); - virtual status_t destroySurface(SurfaceID surfaceId); - virtual status_t onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); - - // constant - sp<SurfaceFlinger> mFlinger; - - // protected by mLock - DefaultKeyedVector< size_t, wp<LayerBaseClient> > mLayers; - size_t mNameGenerator; - - // thread-safe - mutable Mutex mLock; -}; - -class GraphicBufferAlloc : public BnGraphicBufferAlloc -{ +class GraphicBufferAlloc : public BnGraphicBufferAlloc { public: GraphicBufferAlloc(); virtual ~GraphicBufferAlloc(); @@ -102,135 +77,66 @@ public: // --------------------------------------------------------------------------- -class GraphicPlane -{ -public: - static status_t orientationToTransfrom(int orientation, int w, int h, - Transform* tr); - - GraphicPlane(); - ~GraphicPlane(); - - bool initialized() const; - - void setDisplayHardware(DisplayHardware *); - status_t setOrientation(int orientation); - int getOrientation() const { return mOrientation; } - int getWidth() const; - int getHeight() const; - - const DisplayHardware& displayHardware() const; - DisplayHardware& editDisplayHardware(); - const Transform& transform() const; - EGLDisplay getEGLDisplay() const; - -private: - GraphicPlane(const GraphicPlane&); - GraphicPlane operator = (const GraphicPlane&); - - DisplayHardware* mHw; - Transform mGlobalTransform; - Transform mDisplayTransform; - int mOrientation; - float mDisplayWidth; - float mDisplayHeight; - int mWidth; - int mHeight; -}; - -// --------------------------------------------------------------------------- - enum { - eTransactionNeeded = 0x01, - eTraversalNeeded = 0x02 + eTransactionNeeded = 0x01, + eTraversalNeeded = 0x02, + eDisplayTransactionNeeded = 0x04, + eTransactionMask = 0x07 }; -class SurfaceFlinger : - public BinderService<SurfaceFlinger>, - public BnSurfaceComposer, - public IBinder::DeathRecipient, - protected Thread +class SurfaceFlinger : public BinderService<SurfaceFlinger>, + public BnSurfaceComposer, + private IBinder::DeathRecipient, + private Thread, + private HWComposer::EventHandler { public: - static char const* getServiceName() { return "SurfaceFlinger"; } - - SurfaceFlinger(); - virtual ~SurfaceFlinger(); - void init(); + static char const* getServiceName() { + return "SurfaceFlinger"; + } - virtual status_t onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); + SurfaceFlinger(); - virtual status_t dump(int fd, const Vector<String16>& args); - - // ISurfaceComposer interface - virtual sp<ISurfaceComposerClient> createConnection(); - virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc(); - virtual sp<IMemoryHeap> getCblk() const; - virtual void bootFinished(); - virtual void setTransactionState(const Vector<ComposerState>& state, - int orientation, uint32_t flags); - virtual bool authenticateSurfaceTexture(const sp<ISurfaceTexture>& surface) const; - virtual sp<IDisplayEventConnection> createDisplayEventConnection(); - - virtual status_t captureScreen(DisplayID dpy, - sp<IMemoryHeap>* heap, - uint32_t* width, uint32_t* height, - PixelFormat* format, uint32_t reqWidth, uint32_t reqHeight, - uint32_t minLayerZ, uint32_t maxLayerZ); - - virtual status_t turnElectronBeamOff(int32_t mode); - virtual status_t turnElectronBeamOn(int32_t mode); - - - // called when screen needs to turn off - void screenReleased(); - // called when screen is turning back on - void screenAcquired(); - - // called on the main thread in response to screenReleased() - void onScreenReleased(); - // called on the main thread in response to screenAcquired() - void onScreenAcquired(); + enum { + EVENT_VSYNC = HWC_EVENT_VSYNC + }; + // post an asynchronous message to the main thread + status_t postMessageAsync(const sp<MessageBase>& msg, nsecs_t reltime = 0, + uint32_t flags = 0); - status_t renderScreenToTexture(DisplayID dpy, - GLuint* textureName, GLfloat* uOut, GLfloat* vOut); - status_t renderScreenToTextureLocked(DisplayID dpy, - GLuint* textureName, GLfloat* uOut, GLfloat* vOut); + // post a synchronous message to the main thread + status_t postMessageSync(const sp<MessageBase>& msg, nsecs_t reltime = 0, + uint32_t flags = 0); - void onMessageReceived(int32_t what); + // force full composition on all displays + void repaintEverything(); - status_t postMessageAsync(const sp<MessageBase>& msg, - nsecs_t reltime=0, uint32_t flags = 0); + // renders content on given display to a texture. thread-safe version. + status_t renderScreenToTexture(DisplayID dpy, GLuint* textureName, + GLfloat* uOut, GLfloat* vOut); - status_t postMessageSync(const sp<MessageBase>& msg, - nsecs_t reltime=0, uint32_t flags = 0); + // renders content on given display to a texture, w/o acquiring main lock + status_t renderScreenToTextureLocked(DisplayID dpy, GLuint* textureName, + GLfloat* uOut, GLfloat* vOut); - status_t removeLayer(const sp<LayerBase>& layer); - status_t addLayer(const sp<LayerBase>& layer); - status_t invalidateLayerVisibility(const sp<LayerBase>& layer); - void invalidateHwcGeometry(); + // returns the default Display + sp<const DisplayDevice> getDefaultDisplayDevice() const { + return getDisplayDevice(DisplayDevice::DISPLAY_ID_MAIN); + } - sp<Layer> getLayer(const sp<ISurface>& sur) const; + // utility function to delete a texture on the main thread + void deleteTextureAsync(GLuint texture); - GLuint getProtectedTexName() const { return mProtectedTexName; } + // enable/disable h/w composer event + // TODO: this should be made accessible only to EventThread + void eventControl(int event, int enabled); - class MessageDestroyGLTexture : public MessageBase { - GLuint texture; - public: - MessageDestroyGLTexture(GLuint texture) : texture(texture) { } - virtual bool handler() { - glDeleteTextures(1, &texture); - return true; - } - }; - - -private: - // DeathRecipient interface - virtual void binderDied(const wp<IBinder>& who); + // called on the main thread by MessageQueue when an internal message + // is received + // TODO: this should be made accessible only to MessageQueue + void onMessageReceived(int32_t what); private: friend class Client; @@ -239,190 +145,297 @@ private: friend class LayerBaseClient; friend class Layer; - sp<ISurface> createSurface( - ISurfaceComposerClient::surface_data_t* params, - const String8& name, - const sp<Client>& client, - DisplayID display, uint32_t w, uint32_t h, PixelFormat format, - uint32_t flags); - - sp<Layer> createNormalSurface( - const sp<Client>& client, DisplayID display, - uint32_t w, uint32_t h, uint32_t flags, - PixelFormat& format); - - sp<LayerDim> createDimSurface( - const sp<Client>& client, DisplayID display, - uint32_t w, uint32_t h, uint32_t flags); + // We're reference counted, never destroy SurfaceFlinger directly + virtual ~SurfaceFlinger(); - sp<LayerScreenshot> createScreenshotSurface( - const sp<Client>& client, DisplayID display, - uint32_t w, uint32_t h, uint32_t flags); + /* ------------------------------------------------------------------------ + * Internal data structures + */ - status_t removeSurface(const sp<Client>& client, SurfaceID sid); - status_t destroySurface(const wp<LayerBaseClient>& layer); - uint32_t setClientStateLocked(const sp<Client>& client, const layer_state_t& s); - - class LayerVector : public SortedVector< sp<LayerBase> > { + class LayerVector : public SortedVector<sp<LayerBase> > { public: - LayerVector() { } - LayerVector(const LayerVector& rhs) : SortedVector< sp<LayerBase> >(rhs) { } - virtual int do_compare(const void* lhs, const void* rhs) const { - const sp<LayerBase>& l(*reinterpret_cast<const sp<LayerBase>*>(lhs)); - const sp<LayerBase>& r(*reinterpret_cast<const sp<LayerBase>*>(rhs)); - // sort layers by Z order - uint32_t lz = l->currentState().z; - uint32_t rz = r->currentState().z; - // then by sequence, so we get a stable ordering - return (lz != rz) ? (lz - rz) : (l->sequence - r->sequence); - } + LayerVector(); + LayerVector(const LayerVector& rhs); + virtual int do_compare(const void* lhs, const void* rhs) const; + }; + + struct DisplayDeviceState { + DisplayDeviceState(); + DisplayDeviceState(int32_t id); + int32_t id; + sp<ISurfaceTexture> surface; + uint32_t layerStack; + Rect viewport; + Rect frame; + uint8_t orientation; }; struct State { - State() - : orientation(ISurfaceComposer::eOrientationDefault), - orientationFlags(0) { - } - LayerVector layersSortedByZ; - uint8_t orientation; - uint8_t orientationFlags; + LayerVector layersSortedByZ; + DefaultKeyedVector< wp<IBinder>, DisplayDeviceState> displays; }; - virtual bool threadLoop(); - virtual status_t readyToRun(); - virtual void onFirstRef(); + /* ------------------------------------------------------------------------ + * IBinder interface + */ + virtual status_t onTransact(uint32_t code, const Parcel& data, + Parcel* reply, uint32_t flags); + virtual status_t dump(int fd, const Vector<String16>& args); -public: // hack to work around gcc 4.0.3 bug - const GraphicPlane& graphicPlane(int dpy) const; - GraphicPlane& graphicPlane(int dpy); + /* ------------------------------------------------------------------------ + * ISurfaceComposer interface + */ + virtual sp<ISurfaceComposerClient> createConnection(); + virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc(); + virtual sp<IBinder> createDisplay(); + virtual sp<IBinder> getBuiltInDisplay(int32_t id); + virtual void setTransactionState(const Vector<ComposerState>& state, + const Vector<DisplayState>& displays, uint32_t flags); + virtual void bootFinished(); + virtual bool authenticateSurfaceTexture( + const sp<ISurfaceTexture>& surface) const; + virtual sp<IDisplayEventConnection> createDisplayEventConnection(); + virtual status_t captureScreen(DisplayID dpy, sp<IMemoryHeap>* heap, + uint32_t* width, uint32_t* height, PixelFormat* format, + uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, + uint32_t maxLayerZ); + // called when screen needs to turn off + virtual void blank(); + // called when screen is turning back on + virtual void unblank(); + virtual status_t getDisplayInfo(DisplayID dpy, DisplayInfo* info); + virtual void connectDisplay(const sp<ISurfaceTexture> display); + + /* ------------------------------------------------------------------------ + * DeathRecipient interface + */ + virtual void binderDied(const wp<IBinder>& who); - void signalTransaction(); - void signalLayerUpdate(); - void signalRefresh(); - void repaintEverything(); + /* ------------------------------------------------------------------------ + * Thread interface + */ + virtual bool threadLoop(); + virtual status_t readyToRun(); + virtual void onFirstRef(); + + /* ------------------------------------------------------------------------ + * HWComposer::EventHandler interface + */ + virtual void onVSyncReceived(int dpy, nsecs_t timestamp); + + /* ------------------------------------------------------------------------ + * Message handling + */ + void waitForEvent(); + void signalTransaction(); + void signalLayerUpdate(); + void signalRefresh(); + + // called on the main thread in response to screenReleased() + void onScreenReleased(); + // called on the main thread in response to screenAcquired() + void onScreenAcquired(); + + void handleMessageTransaction(); + void handleMessageInvalidate(); + void handleMessageRefresh(); + + void handleTransaction(uint32_t transactionFlags); + void handleTransactionLocked(uint32_t transactionFlags); + + /* handlePageFilp: this is were we latch a new buffer + * if available and compute the dirty region. + */ + void handlePageFlip(); + + /* ------------------------------------------------------------------------ + * Transactions + */ + uint32_t getTransactionFlags(uint32_t flags); + uint32_t peekTransactionFlags(uint32_t flags); + uint32_t setTransactionFlags(uint32_t flags); + void commitTransaction(); + uint32_t setClientStateLocked(const sp<Client>& client, + const layer_state_t& s); + uint32_t setDisplayStateLocked(const DisplayState& s); + + /* ------------------------------------------------------------------------ + * Layer management + */ + sp<ISurface> createLayer(ISurfaceComposerClient::surface_data_t* params, + const String8& name, const sp<Client>& client, DisplayID display, + uint32_t w, uint32_t h, PixelFormat format, uint32_t flags); + + sp<Layer> createNormalLayer(const sp<Client>& client, DisplayID display, + uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format); + + sp<LayerDim> createDimLayer(const sp<Client>& client, DisplayID display, + uint32_t w, uint32_t h, uint32_t flags); + + sp<LayerScreenshot> createScreenshotLayer(const sp<Client>& client, + DisplayID display, uint32_t w, uint32_t h, uint32_t flags); + + // called in response to the window-manager calling + // ISurfaceComposerClient::destroySurface() + // The specified layer is first placed in a purgatory list + // until all references from the client are released. + status_t onLayerRemoved(const sp<Client>& client, SurfaceID sid); + + // called when all clients have released all their references to + // this layer meaning it is entirely safe to destroy all + // resources associated to this layer. + status_t onLayerDestroyed(const wp<LayerBaseClient>& layer); + + // remove a layer from SurfaceFlinger immediately + status_t removeLayer(const sp<LayerBase>& layer); -private: - void waitForEvent(); - void handleTransaction(uint32_t transactionFlags); - void handleTransactionLocked(uint32_t transactionFlags); - - void computeVisibleRegions( - const LayerVector& currentLayers, - Region& dirtyRegion, - Region& wormholeRegion); - - void handlePageFlip(); - bool lockPageFlip(const LayerVector& currentLayers); - void unlockPageFlip(const LayerVector& currentLayers); - void handleRefresh(); - void handleWorkList(); - void handleRepaint(); - void postFramebuffer(); - void setupHardwareComposer(); - void composeSurfaces(const Region& dirty); - - - void setInvalidateRegion(const Region& reg); - Region getAndClearInvalidateRegion(); - - ssize_t addClientLayer(const sp<Client>& client, - const sp<LayerBaseClient>& lbc); - status_t addLayer_l(const sp<LayerBase>& layer); - status_t removeLayer_l(const sp<LayerBase>& layer); - status_t purgatorizeLayer_l(const sp<LayerBase>& layer); - - uint32_t getTransactionFlags(uint32_t flags); - uint32_t peekTransactionFlags(uint32_t flags); - uint32_t setTransactionFlags(uint32_t flags); - void commitTransaction(); - - - status_t captureScreenImplLocked(DisplayID dpy, - sp<IMemoryHeap>* heap, - uint32_t* width, uint32_t* height, PixelFormat* format, - uint32_t reqWidth, uint32_t reqHeight, - uint32_t minLayerZ, uint32_t maxLayerZ); - - status_t turnElectronBeamOffImplLocked(int32_t mode); - status_t turnElectronBeamOnImplLocked(int32_t mode); - status_t electronBeamOffAnimationImplLocked(); - status_t electronBeamOnAnimationImplLocked(); - - void debugFlashRegions(); - void drawWormhole() const; - - void startBootAnim(); - - void listLayersLocked(const Vector<String16>& args, size_t& index, - String8& result, char* buffer, size_t SIZE) const; - void dumpStatsLocked(const Vector<String16>& args, size_t& index, - String8& result, char* buffer, size_t SIZE) const; - void clearStatsLocked(const Vector<String16>& args, size_t& index, - String8& result, char* buffer, size_t SIZE) const; - void dumpAllLocked(String8& result, char* buffer, size_t SIZE) const; - - mutable MessageQueue mEventQueue; - - // access must be protected by mStateLock - mutable Mutex mStateLock; - State mCurrentState; - volatile int32_t mTransactionFlags; - Condition mTransactionCV; - SortedVector< sp<LayerBase> > mLayerPurgatory; - bool mTransationPending; - Vector< sp<LayerBase> > mLayersPendingRemoval; - - // protected by mStateLock (but we could use another lock) - GraphicPlane mGraphicPlanes[1]; - bool mLayersRemoved; - DefaultKeyedVector< wp<IBinder>, wp<Layer> > mLayerMap; - - // access must be protected by mInvalidateLock - mutable Mutex mInvalidateLock; - Region mInvalidateRegion; - - // constant members (no synchronization needed for access) - sp<IMemoryHeap> mServerHeap; - surface_flinger_cblk_t* mServerCblk; - GLuint mWormholeTexName; - GLuint mProtectedTexName; - nsecs_t mBootTime; - sp<EventThread> mEventThread; - - // Can only accessed from the main thread, these members - // don't need synchronization - State mDrawingState; - Region mDirtyRegion; - Region mDirtyRegionRemovedLayer; - Region mSwapRegion; - Region mWormholeRegion; - bool mVisibleRegionsDirty; - bool mHwWorkListDirty; - int32_t mElectronBeamAnimationMode; - Vector< sp<LayerBase> > mVisibleLayersSortedByZ; - - - // don't use a lock for these, we don't care - int mDebugRegion; - int mDebugDDMS; - int mDebugDisableHWC; - int mDebugDisableTransformHint; - volatile nsecs_t mDebugInSwapBuffers; - nsecs_t mLastSwapBufferTime; - volatile nsecs_t mDebugInTransaction; - nsecs_t mLastTransactionTime; - bool mBootFinished; - - // these are thread safe - mutable Barrier mReadyToRunBarrier; - - - // protected by mDestroyedLayerLock; - mutable Mutex mDestroyedLayerLock; - Vector<LayerBase const *> mDestroyedLayers; - - // only written in the main thread, only read in other threads - volatile int32_t mSecureFrameBuffer; + // add a layer to SurfaceFlinger + ssize_t addClientLayer(const sp<Client>& client, + const sp<LayerBaseClient>& lbc); + + status_t removeLayer_l(const sp<LayerBase>& layer); + status_t purgatorizeLayer_l(const sp<LayerBase>& layer); + + /* ------------------------------------------------------------------------ + * Boot animation, on/off animations and screen capture + */ + + void startBootAnim(); + + status_t captureScreenImplLocked(DisplayID dpy, sp<IMemoryHeap>* heap, + uint32_t* width, uint32_t* height, PixelFormat* format, + uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, + uint32_t maxLayerZ); + + /* ------------------------------------------------------------------------ + * EGL + */ + static status_t selectConfigForPixelFormat(EGLDisplay dpy, + EGLint const* attrs, PixelFormat format, EGLConfig* outConfig); + static EGLConfig selectEGLConfig(EGLDisplay disp, EGLint visualId); + static EGLContext createGLContext(EGLDisplay disp, EGLConfig config); + void initializeGL(EGLDisplay display, EGLSurface surface); + uint32_t getMaxTextureSize() const; + uint32_t getMaxViewportDims() const; + + /* ------------------------------------------------------------------------ + * Display and layer stack management + */ + sp<const DisplayDevice> getDisplayDevice(DisplayID dpy) const { + return mDisplays.valueFor(dpy); + } + const sp<DisplayDevice>& getDisplayDevice(DisplayID dpy) { + return mDisplays.valueFor(dpy); + } + + // mark a region of a layer stack dirty. this updates the dirty + // region of all screens presenting this layer stack. + void invalidateLayerStack(uint32_t layerStack, const Region& dirty); + + /* ------------------------------------------------------------------------ + * H/W composer + */ + + HWComposer& getHwComposer() const { return *mHwc; } + + /* ------------------------------------------------------------------------ + * Compositing + */ + void invalidateHwcGeometry(); + void computeVisibleRegions(const LayerVector& currentLayers, + uint32_t layerStack, + Region& dirtyRegion, Region& opaqueRegion); + + void preComposition(); + void postComposition(); + void rebuildLayerStacks(); + void setUpHWComposer(); + void doComposition(); + void doDebugFlashRegions(); + void doDisplayComposition(const sp<const DisplayDevice>& hw, + const Region& dirtyRegion); + void doComposeSurfaces(const sp<const DisplayDevice>& hw, + const Region& dirty); + + void postFramebuffer(); + void drawWormhole(const Region& region) const; + GLuint getProtectedTexName() const { + return mProtectedTexName; + } + + /* ------------------------------------------------------------------------ + * Debugging & dumpsys + */ + void listLayersLocked(const Vector<String16>& args, size_t& index, + String8& result, char* buffer, size_t SIZE) const; + void dumpStatsLocked(const Vector<String16>& args, size_t& index, + String8& result, char* buffer, size_t SIZE) const; + void clearStatsLocked(const Vector<String16>& args, size_t& index, + String8& result, char* buffer, size_t SIZE) const; + void dumpAllLocked(String8& result, char* buffer, size_t SIZE) const; + + /* ------------------------------------------------------------------------ + * Attributes + */ + + // access must be protected by mStateLock + mutable Mutex mStateLock; + State mCurrentState; + volatile int32_t mTransactionFlags; + Condition mTransactionCV; + SortedVector<sp<LayerBase> > mLayerPurgatory; + bool mTransationPending; + Vector<sp<LayerBase> > mLayersPendingRemoval; + + // protected by mStateLock (but we could use another lock) + bool mLayersRemoved; + + // access must be protected by mInvalidateLock + volatile int32_t mRepaintEverything; + + // constant members (no synchronization needed for access) + HWComposer* mHwc; + GLuint mProtectedTexName; + nsecs_t mBootTime; + sp<EventThread> mEventThread; + GLint mMaxViewportDims[2]; + GLint mMaxTextureSize; + EGLContext mEGLContext; + EGLConfig mEGLConfig; + EGLDisplay mEGLDisplay; + sp<IBinder> mDefaultDisplays[DisplayDevice::DISPLAY_ID_COUNT]; + + // Can only accessed from the main thread, these members + // don't need synchronization + State mDrawingState; + bool mVisibleRegionsDirty; + bool mHwWorkListDirty; + DefaultKeyedVector<int32_t, sp<DisplayDevice> > mDisplays; + + // don't use a lock for these, we don't care + int mDebugRegion; + int mDebugDDMS; + int mDebugDisableHWC; + int mDebugDisableTransformHint; + volatile nsecs_t mDebugInSwapBuffers; + nsecs_t mLastSwapBufferTime; + volatile nsecs_t mDebugInTransaction; + nsecs_t mLastTransactionTime; + bool mBootFinished; + + // these are thread safe + mutable MessageQueue mEventQueue; + mutable Barrier mReadyToRunBarrier; + + // protected by mDestroyedLayerLock; + mutable Mutex mDestroyedLayerLock; + Vector<LayerBase const *> mDestroyedLayers; + + /* ------------------------------------------------------------------------ + * Feature prototyping + */ + + sp<IBinder> mExtDisplayToken; }; // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp index 84ae0d9..e3a98ff 100644 --- a/services/surfaceflinger/tests/Transaction_test.cpp +++ b/services/surfaceflinger/tests/Transaction_test.cpp @@ -24,6 +24,7 @@ #include <private/gui/ComposerService.h> #include <utils/String8.h> +#include <ui/DisplayInfo.h> namespace android { @@ -92,8 +93,11 @@ protected: mComposerClient = new SurfaceComposerClient; ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); - ssize_t displayWidth = mComposerClient->getDisplayWidth(0); - ssize_t displayHeight = mComposerClient->getDisplayHeight(0); + DisplayInfo info; + SurfaceComposerClient::getDisplayInfo(0, &info); + + ssize_t displayWidth = info.w; + ssize_t displayHeight = info.h; // Background surface mBGSurfaceControl = mComposerClient->createSurface( |