Merge changes 24119,24120 into eclair

* changes:
  delete old and unused source files
  fix [2068105] implement queueBuffer/lockBuffer/dequeueBuffer properly
This commit is contained in:
Android (Google) Code Review
2009-09-08 14:36:06 -07:00
39 changed files with 1277 additions and 3138 deletions

View File

@ -25,8 +25,6 @@
#include <ui/ISurfaceFlingerClient.h>
#include <ui/Region.h>
#include <private/ui/SharedState.h>
namespace android {
class Parcel;

View File

@ -0,0 +1,327 @@
/*
* 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_UI_SHARED_BUFFER_STACK_H
#define ANDROID_UI_SHARED_BUFFER_STACK_H
#include <stdint.h>
#include <sys/types.h>
#include <cutils/compiler.h>
#include <utils/Debug.h>
#include <utils/threads.h>
#include <utils/String8.h>
#include <ui/Rect.h>
namespace android {
// ---------------------------------------------------------------------------
/*
* These classes manage a stack of buffers in shared memory.
*
* SharedClient: represents a client with several stacks
* SharedBufferStack: represents a stack of buffers
* SharedBufferClient: manipulates the SharedBufferStack from the client side
* SharedBufferServer: manipulates the SharedBufferStack from the server side
*
* Buffers can be dequeued until there are none available, they can be locked
* unless they are in use by the server, which is only the case for the last
* dequeue-able buffer. When these various conditions are not met, the caller
* waits until the condition is met.
*
*
* CAVEATS:
*
* In the current implementation there are several limitations:
* - buffers must be locked in the same order they've been dequeued
* - buffers must be enqueued in the same order they've been locked
* - dequeue() is not reentrant
* - no error checks are done on the condition above
*
*/
// When changing these values, the COMPILE_TIME_ASSERT at the end of this
// file need to be updated.
const unsigned int NUM_LAYERS_MAX = 31;
const unsigned int NUM_BUFFER_MAX = 4;
const unsigned int NUM_DISPLAY_MAX = 4;
// ----------------------------------------------------------------------------
class Region;
class SharedBufferStack;
class SharedClient;
// ----------------------------------------------------------------------------
struct FlatRegion { // 12 bytes
static const unsigned int NUM_RECT_MAX = 1;
uint32_t count;
uint16_t rects[4*NUM_RECT_MAX];
};
// should be 128 bytes (32 longs)
class SharedBufferStack
{
friend class SharedClient;
friend class SharedBufferBase;
friend class SharedBufferClient;
friend class SharedBufferServer;
public:
SharedBufferStack();
status_t setDirtyRegion(int buffer, const Region& reg);
Region getDirtyRegion(int buffer) const;
// these attributes are part of the conditions/updates
volatile int32_t head; // server's current front buffer
volatile int32_t available; // number of dequeue-able buffers
volatile int32_t queued; // number of buffers waiting for post
volatile int32_t inUse; // buffer currently in use by SF
// not part of the conditions
volatile int32_t reallocMask;
int32_t identity; // surface's identity (const)
status_t status; // surface's status code
int32_t reserved32[13];
FlatRegion dirtyRegion[NUM_BUFFER_MAX]; // 12*4=48 bytes
};
// ----------------------------------------------------------------------------
// 4 KB max
class SharedClient
{
public:
SharedClient();
~SharedClient();
status_t validate(size_t token) const;
uint32_t getIdentity(size_t token) const;
status_t setIdentity(size_t token, uint32_t identity);
private:
friend class SharedBufferBase;
friend class SharedBufferClient;
friend class SharedBufferServer;
// FIXME: this should be replaced by a lock-less primitive
Mutex lock;
Condition cv;
SharedBufferStack surfaces[ NUM_LAYERS_MAX ];
};
// ============================================================================
class SharedBufferBase
{
public:
SharedBufferBase(SharedClient* sharedClient, int surface, int num);
~SharedBufferBase();
uint32_t getIdentity();
size_t getFrontBuffer() const;
String8 dump(char const* prefix) const;
protected:
SharedClient* const mSharedClient;
SharedBufferStack* const mSharedStack;
const int mNumBuffers;
friend struct Update;
friend struct QueueUpdate;
struct ConditionBase {
SharedBufferStack& stack;
inline ConditionBase(SharedBufferBase* sbc)
: stack(*sbc->mSharedStack) { }
};
struct UpdateBase {
SharedBufferStack& stack;
inline UpdateBase(SharedBufferBase* sbb)
: stack(*sbb->mSharedStack) { }
};
template <typename T>
status_t waitForCondition(T condition);
template <typename T>
status_t updateCondition(T update);
};
template <typename T>
status_t SharedBufferBase::waitForCondition(T condition)
{
SharedClient& client( *mSharedClient );
const nsecs_t TIMEOUT = s2ns(1);
Mutex::Autolock _l(client.lock);
while (!condition()) {
status_t err = client.cv.waitRelative(client.lock, TIMEOUT);
// handle errors and timeouts
if (CC_UNLIKELY(err != NO_ERROR)) {
if (err == TIMED_OUT) {
if (condition()) {
LOGE("waitForCondition(%s) timed out (identity=%d), "
"but condition is true! We recovered but it "
"shouldn't happen." ,
T::name(), mSharedStack->identity);
break;
} else {
LOGW("waitForCondition(%s) timed out (identity=%d). "
"CPU may be pegged. trying again.",
T::name(), mSharedStack->identity);
}
} else {
LOGE("waitForCondition(%s) error (%s) ",
T::name(), strerror(-err));
return err;
}
}
}
return NO_ERROR;
}
template <typename T>
status_t SharedBufferBase::updateCondition(T update) {
SharedClient& client( *mSharedClient );
Mutex::Autolock _l(client.lock);
ssize_t result = update();
client.cv.broadcast();
return result;
}
// ----------------------------------------------------------------------------
class SharedBufferClient : public SharedBufferBase
{
public:
SharedBufferClient(SharedClient* sharedClient, int surface, int num);
ssize_t dequeue();
status_t undoDequeue(int buf);
status_t lock(int buf);
status_t queue(int buf);
bool needNewBuffer(int buffer) const;
status_t setDirtyRegion(int buffer, const Region& reg);
private:
friend struct Condition;
friend struct DequeueCondition;
friend struct LockCondition;
struct QueueUpdate : public UpdateBase {
inline QueueUpdate(SharedBufferBase* sbb);
inline ssize_t operator()();
};
struct UndoDequeueUpdate : public UpdateBase {
inline UndoDequeueUpdate(SharedBufferBase* sbb);
inline ssize_t operator()();
};
// --
struct DequeueCondition : public ConditionBase {
inline DequeueCondition(SharedBufferClient* sbc);
inline bool operator()();
static inline const char* name() { return "DequeueCondition"; }
};
struct LockCondition : public ConditionBase {
int buf;
inline LockCondition(SharedBufferClient* sbc, int buf);
inline bool operator()();
static inline const char* name() { return "LockCondition"; }
};
int32_t tail;
};
// ----------------------------------------------------------------------------
class SharedBufferServer : public SharedBufferBase
{
public:
SharedBufferServer(SharedClient* sharedClient, int surface, int num);
ssize_t retireAndLock();
status_t unlock(int buffer);
status_t reallocate();
status_t assertReallocate(int buffer);
Region getDirtyRegion(int buffer) const;
private:
struct UnlockUpdate : public UpdateBase {
const int lockedBuffer;
inline UnlockUpdate(SharedBufferBase* sbb, int lockedBuffer);
inline ssize_t operator()();
};
struct RetireUpdate : public UpdateBase {
const int numBuffers;
inline RetireUpdate(SharedBufferBase* sbb, int numBuffers);
inline ssize_t operator()();
};
struct ReallocateCondition : public ConditionBase {
int buf;
inline ReallocateCondition(SharedBufferBase* sbb, int buf);
inline bool operator()();
static inline const char* name() { return "ReallocateCondition"; }
};
};
// ===========================================================================
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];
};
// ---------------------------------------------------------------------------
COMPILE_TIME_ASSERT(sizeof(SharedClient) <= 4096)
COMPILE_TIME_ASSERT(sizeof(SharedBufferStack) == 128)
COMPILE_TIME_ASSERT(sizeof(surface_flinger_cblk_t) <= 4096)
// ---------------------------------------------------------------------------
}; // namespace android
#endif /* ANDROID_UI_SHARED_BUFFER_STACK_H */

View File

@ -1,154 +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_UI_SHARED_STATE_H
#define ANDROID_UI_SHARED_STATE_H
#include <stdint.h>
#include <sys/types.h>
#include <utils/Debug.h>
#include <utils/threads.h>
namespace android {
/*
* These structures are shared between the composer process and its clients
*/
// ---------------------------------------------------------------------------
struct surface_info_t { // 4 longs, 16 bytes
enum {
eBufferDirty = 0x01,
eNeedNewBuffer = 0x02
};
uint8_t reserved[11];
uint8_t flags;
status_t status;
};
// ---------------------------------------------------------------------------
const uint32_t NUM_LAYERS_MAX = 31;
enum { // layer_cblk_t swapState
eIndex = 0x00000001,
eFlipRequested = 0x00000002,
eResizeBuffer0 = 0x00000004,
eResizeBuffer1 = 0x00000008,
eResizeRequested = eResizeBuffer0 | eResizeBuffer1,
eBusy = 0x00000010,
eLocked = 0x00000020,
eNextFlipPending = 0x00000040,
eInvalidSurface = 0x00000080
};
enum { // layer_cblk_t flags
eLayerNotPosted = 0x00000001,
eNoCopyBack = 0x00000002,
eReserved = 0x0000007C,
eBufferIndexShift = 7,
eBufferIndex = 1<<eBufferIndexShift,
};
struct flat_region_t // 40 bytes
{
int32_t count;
int16_t l;
int16_t t;
int16_t r;
int16_t b;
uint16_t runs[14];
};
struct layer_cblk_t // (128 bytes)
{
volatile int32_t swapState; // 4
volatile int32_t flags; // 4
volatile int32_t identity; // 4
int32_t reserved; // 4
surface_info_t surface[2]; // 32
flat_region_t region[2]; // 80
static inline int backBuffer(uint32_t state) {
return ((state & eIndex) ^ ((state & eFlipRequested)>>1));
}
static inline int frontBuffer(uint32_t state) {
return 1 - backBuffer(state);
}
};
// ---------------------------------------------------------------------------
struct per_client_cblk_t // 4KB max
{
per_client_cblk_t() : lock(Mutex::SHARED) { }
Mutex lock;
Condition cv;
layer_cblk_t layers[NUM_LAYERS_MAX] __attribute__((aligned(32)));
enum {
BLOCKING = 0x00000001,
INSPECT = 0x00000002
};
// these functions are used by the clients
status_t validate(size_t i) const;
int32_t lock_layer(size_t i, uint32_t flags);
uint32_t unlock_layer_and_post(size_t i);
void unlock_layer(size_t i);
};
// ---------------------------------------------------------------------------
const uint32_t 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];
};
// ---------------------------------------------------------------------------
COMPILE_TIME_ASSERT(sizeof(layer_cblk_t) == 128)
COMPILE_TIME_ASSERT(sizeof(per_client_cblk_t) <= 4096)
COMPILE_TIME_ASSERT(sizeof(surface_flinger_cblk_t) <= 4096)
// ---------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_UI_SHARED_STATE_H

View File

@ -47,6 +47,9 @@ public:
status_t lock(uint32_t usage, const Rect& rect, void** vaddr);
status_t unlock();
void setIndex(int index);
int getIndex() const;
protected:
SurfaceBuffer();
SurfaceBuffer(const Parcel& reply);
@ -69,6 +72,7 @@ private:
android_native_buffer_t const* buffer);
BufferMapper& mBufferMapper;
int mIndex;
};
}; // namespace android

View File

@ -44,13 +44,13 @@ protected:
UNREGISTER_BUFFERS,
POST_BUFFER, // one-way transaction
CREATE_OVERLAY,
GET_BUFFER,
REQUEST_BUFFER,
};
public:
DECLARE_META_INTERFACE(Surface);
virtual sp<SurfaceBuffer> getBuffer(int usage) = 0;
virtual sp<SurfaceBuffer> requestBuffer(int bufferIdx, int usage) = 0;
class BufferHeap {
public:

View File

@ -39,8 +39,8 @@ class IOMX;
class Rect;
class Surface;
class SurfaceComposerClient;
struct per_client_cblk_t;
struct layer_cblk_t;
class SharedClient;
class SharedBufferClient;
// ---------------------------------------------------------------------------
@ -109,7 +109,7 @@ private:
~SurfaceControl();
status_t validate(per_client_cblk_t const* cblk) const;
status_t validate(SharedClient const* cblk) const;
void destroy();
sp<SurfaceComposerClient> mClient;
@ -190,8 +190,7 @@ private:
status_t getBufferLocked(int index, int usage);
status_t validate(per_client_cblk_t const* cblk) const;
static void _send_dirty_region(layer_cblk_t* lcblk, const Region& dirty);
status_t validate(SharedClient const* cblk) const;
inline const BufferMapper& getBufferMapper() const { return mBufferMapper; }
inline BufferMapper& getBufferMapper() { return mBufferMapper; }
@ -210,11 +209,10 @@ private:
int perform(int operation, va_list args);
status_t dequeueBuffer(sp<SurfaceBuffer>* buffer);
status_t lockBuffer(const sp<SurfaceBuffer>& buffer);
status_t queueBuffer(const sp<SurfaceBuffer>& buffer);
void setUsage(uint32_t reqUsage);
bool getUsage(uint32_t* usage);
// constants
sp<SurfaceComposerClient> mClient;
@ -224,21 +222,23 @@ private:
PixelFormat mFormat;
uint32_t mFlags;
BufferMapper& mBufferMapper;
SharedBufferClient* mSharedBufferClient;
// protected by mSurfaceLock
Rect mSwapRectangle;
uint32_t mUsage;
bool mUsageChanged;
int32_t mUsageChanged;
// protected by mSurfaceLock. These are also used from lock/unlock
// but in that case, they must be called form the same thread.
sp<SurfaceBuffer> mBuffers[2];
mutable Region mDirtyRegion;
mutable uint8_t mBackbufferIndex;
// must be used from the lock/unlock thread
sp<SurfaceBuffer> mLockedBuffer;
sp<SurfaceBuffer> mPostedBuffer;
mutable Region mOldDirtyRegion;
bool mNeedFullUpdate;
// query() must be called from dequeueBuffer() thread
uint32_t mWidth;
@ -246,6 +246,7 @@ private:
// Inherently thread-safe
mutable Mutex mSurfaceLock;
mutable Mutex mApiLock;
};
}; // namespace android

View File

@ -21,7 +21,6 @@
#include <sys/types.h>
#include <utils/SortedVector.h>
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
#include <utils/threads.h>
@ -36,8 +35,7 @@ namespace android {
class Region;
class SurfaceFlingerSynchro;
struct per_client_cblk_t;
struct layer_cblk_t;
class SharedClient;
class SurfaceComposerClient : virtual public RefBase
{
@ -63,12 +61,12 @@ public:
//! Create a surface
sp<SurfaceControl> createSurface(
int pid, //!< pid of the process the surfacec is for
DisplayID display, //!< Display to create this surface on
uint32_t w, //!< width in pixel
uint32_t h, //!< height in pixel
PixelFormat format, //!< pixel-format desired
uint32_t flags = 0 //!< usage flags
int pid, // pid of the process the surface is for
DisplayID display, // Display to create this surface on
uint32_t w, // width in pixel
uint32_t h, // height in pixel
PixelFormat format, // pixel-format desired
uint32_t flags = 0 // usage flags
);
// ------------------------------------------------------------------------
@ -148,7 +146,7 @@ private:
// these don't need to be protected because they never change
// after assignment
status_t mStatus;
per_client_cblk_t* mControl;
SharedClient* mControl;
sp<IMemoryHeap> mControlMemory;
sp<ISurfaceFlingerClient> mClient;
SurfaceFlingerSynchro* mSignalServer;

View File

@ -63,7 +63,7 @@ enum {
BAD_INDEX = -EOVERFLOW,
NOT_ENOUGH_DATA = -ENODATA,
WOULD_BLOCK = -EWOULDBLOCK,
TIMED_OUT = -ETIME,
TIMED_OUT = -ETIMEDOUT,
UNKNOWN_TRANSACTION = -EBADMSG,
#else
BAD_INDEX = -E2BIG,

View File

@ -6,12 +6,12 @@ LOCAL_SRC_FILES:= \
DisplayHardware/DisplayHardware.cpp \
DisplayHardware/DisplayHardwareBase.cpp \
BlurFilter.cpp.arm \
Buffer.cpp \
BufferAllocator.cpp \
Layer.cpp \
LayerBase.cpp \
LayerBuffer.cpp \
LayerBlur.cpp \
LayerBitmap.cpp \
LayerDim.cpp \
MessageQueue.cpp \
SurfaceFlinger.cpp \

View File

@ -27,8 +27,8 @@
#include <ui/Surface.h>
#include <pixelflinger/pixelflinger.h>
#include "Buffer.h"
#include "BufferAllocator.h"
#include "LayerBitmap.h"
#include "SurfaceFlinger.h"
@ -38,15 +38,16 @@ namespace android {
// Buffer and implementation of android_native_buffer_t
// ===========================================================================
Buffer::Buffer()
: SurfaceBuffer(), mInitCheck(NO_ERROR), mVStride(0)
{
}
Buffer::Buffer(uint32_t w, uint32_t h, PixelFormat format,
uint32_t reqUsage, uint32_t flags)
: SurfaceBuffer(), mInitCheck(NO_INIT), mFlags(flags),
mVStride(0)
: SurfaceBuffer(), mInitCheck(NO_INIT), mVStride(0)
{
this->format = format;
if (w>0 && h>0) {
mInitCheck = initSize(w, h, reqUsage);
}
mInitCheck = initSize(w, h, format, reqUsage, flags);
}
Buffer::~Buffer()
@ -66,7 +67,19 @@ android_native_buffer_t* Buffer::getNativeBuffer() const
return static_cast<android_native_buffer_t*>(const_cast<Buffer*>(this));
}
status_t Buffer::initSize(uint32_t w, uint32_t h, uint32_t reqUsage)
status_t Buffer::reallocate(uint32_t w, uint32_t h, PixelFormat f,
uint32_t reqUsage, uint32_t flags)
{
if (handle) {
BufferAllocator& allocator(BufferAllocator::get());
allocator.free(handle);
handle = 0;
}
return initSize(w, h, f, reqUsage, flags);
}
status_t Buffer::initSize(uint32_t w, uint32_t h, PixelFormat format,
uint32_t reqUsage, uint32_t flags)
{
status_t err = NO_ERROR;
@ -84,7 +97,7 @@ status_t Buffer::initSize(uint32_t w, uint32_t h, uint32_t reqUsage)
*
*/
if (mFlags & Buffer::SECURE) {
if (flags & Buffer::SECURE) {
// secure buffer, don't store it into the GPU
usage = BufferAllocator::USAGE_SW_READ_OFTEN |
BufferAllocator::USAGE_SW_WRITE_OFTEN;
@ -95,10 +108,10 @@ status_t Buffer::initSize(uint32_t w, uint32_t h, uint32_t reqUsage)
}
err = allocator.alloc(w, h, format, usage, &handle, &stride);
if (err == NO_ERROR) {
width = w;
height = h;
this->width = w;
this->height = h;
this->format = format;
mVStride = 0;
}
@ -121,78 +134,6 @@ status_t Buffer::lock(GGLSurface* sur, uint32_t usage)
return res;
}
// ===========================================================================
// LayerBitmap
// ===========================================================================
LayerBitmap::LayerBitmap()
: mInfo(0), mWidth(0), mHeight(0)
{
}
LayerBitmap::~LayerBitmap()
{
}
status_t LayerBitmap::init(surface_info_t* info,
uint32_t w, uint32_t h, PixelFormat format, uint32_t flags)
{
if (info == NULL)
return BAD_VALUE;
mFormat = format;
mFlags = flags;
mWidth = w;
mHeight = h;
mInfo = info;
memset(info, 0, sizeof(surface_info_t));
info->flags = surface_info_t::eNeedNewBuffer;
// init the buffer, but don't trigger an allocation
mBuffer = new Buffer(0, 0, format, flags);
return NO_ERROR;
}
status_t LayerBitmap::setSize(uint32_t w, uint32_t h)
{
Mutex::Autolock _l(mLock);
if ((w != mWidth) || (h != mHeight)) {
mWidth = w;
mHeight = h;
// this will signal the client that it needs to asks us for a new buffer
mInfo->flags = surface_info_t::eNeedNewBuffer;
}
return NO_ERROR;
}
sp<Buffer> LayerBitmap::allocate(uint32_t reqUsage)
{
Mutex::Autolock _l(mLock);
surface_info_t* info = mInfo;
mBuffer.clear(); // free buffer before allocating a new one
sp<Buffer> buffer = new Buffer(mWidth, mHeight, mFormat, reqUsage, mFlags);
status_t err = buffer->initCheck();
if (LIKELY(err == NO_ERROR)) {
info->flags = surface_info_t::eBufferDirty;
info->status = NO_ERROR;
} else {
memset(info, 0, sizeof(surface_info_t));
info->status = NO_MEMORY;
}
mBuffer = buffer;
return buffer;
}
status_t LayerBitmap::free()
{
mBuffer.clear();
mWidth = 0;
mHeight = 0;
return NO_ERROR;
}
// ---------------------------------------------------------------------------
}; // namespace android

View File

@ -30,7 +30,7 @@
#include <pixelflinger/pixelflinger.h>
#include <private/ui/SharedState.h>
#include <private/ui/SharedBufferStack.h>
#include <private/ui/SurfaceBuffer.h>
class copybit_image_t;
@ -38,10 +38,6 @@ struct android_native_buffer_t;
namespace android {
// ---------------------------------------------------------------------------
class IMemory;
class LayerBitmap;
// ===========================================================================
// Buffer
// ===========================================================================
@ -56,6 +52,8 @@ public:
SECURE = 0x00000004
};
Buffer();
// creates w * h buffer
Buffer(uint32_t w, uint32_t h, PixelFormat format,
uint32_t reqUsage, uint32_t flags = 0);
@ -74,6 +72,9 @@ public:
android_native_buffer_t* getNativeBuffer() const;
status_t reallocate(uint32_t w, uint32_t h, PixelFormat f,
uint32_t reqUsage, uint32_t flags);
private:
friend class LightRefBase<Buffer>;
Buffer(const Buffer& rhs);
@ -81,52 +82,11 @@ private:
Buffer& operator = (const Buffer& rhs);
const Buffer& operator = (const Buffer& rhs) const;
status_t initSize(uint32_t w, uint32_t h, uint32_t reqUsage);
status_t initSize(uint32_t w, uint32_t h, PixelFormat format,
uint32_t reqUsage, uint32_t flags);
ssize_t mInitCheck;
uint32_t mFlags;
uint32_t mVStride;
};
// ===========================================================================
// LayerBitmap
// ===========================================================================
class LayerBitmap
{
public:
enum {
DONT_CLEAR = Buffer::DONT_CLEAR,
SECURE = Buffer::SECURE
};
LayerBitmap();
~LayerBitmap();
status_t init(surface_info_t* info,
uint32_t w, uint32_t h, PixelFormat format, uint32_t flags = 0);
status_t setSize(uint32_t w, uint32_t h);
sp<Buffer> allocate(uint32_t reqUsage);
status_t free();
sp<const Buffer> getBuffer() const { return mBuffer; }
sp<Buffer> getBuffer() { return mBuffer; }
uint32_t getWidth() const { return mWidth; }
uint32_t getHeight() const { return mHeight; }
PixelFormat getPixelFormat() const { return mBuffer->getPixelFormat(); }
Rect getBounds() const { return mBuffer->getBounds(); }
private:
surface_info_t* mInfo;
sp<Buffer> mBuffer;
uint32_t mWidth;
uint32_t mHeight;
PixelFormat mFormat;
uint32_t mFlags;
// protects setSize() and allocate()
mutable Mutex mLock;
ssize_t mInitCheck;
uint32_t mVStride;
};
}; // namespace android

View File

@ -71,14 +71,23 @@ void BufferAllocator::dump(String8& result) const
result.append(buffer);
}
static inline uint32_t clamp(uint32_t c) {
return c>0 ? c : 1;
}
status_t BufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat format,
int usage, buffer_handle_t* handle, int32_t* stride)
{
Mutex::Autolock _l(mLock);
// make sure to not allocate a 0 x 0 buffer
w = clamp(w);
h = clamp(h);
// we have a h/w allocator and h/w buffer is requested
status_t err = mAllocDev->alloc(mAllocDev,
w, h, format, usage, handle, stride);
LOGW_IF(err, "alloc(%u, %u, %d, %08x, ...) failed %d (%s)",
w, h, format, usage, err, strerror(-err));

View File

@ -46,22 +46,25 @@ using namespace android;
static __attribute__((noinline))
void checkGLErrors()
{
GLenum error = glGetError();
if (error != GL_NO_ERROR)
do {
// there could be more than one error flag
GLenum error = glGetError();
if (error == GL_NO_ERROR)
break;
LOGE("GL error 0x%04x", int(error));
} while(true);
}
static __attribute__((noinline))
void checkEGLErrors(const char* token)
{
EGLint error = eglGetError();
// GLESonGL seems to be returning 0 when there is no errors?
if (error && error != EGL_SUCCESS)
LOGE("%s error 0x%04x (%s)",
if (error && error != EGL_SUCCESS) {
LOGE("%s: EGL error 0x%04x (%s)",
token, int(error), EGLUtils::strerror(error));
}
}
/*
* Initialize the display to the specified values.
*
@ -158,7 +161,6 @@ void DisplayHardware::init(uint32_t dpy)
*/
surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL);
checkEGLErrors("eglCreateWindowSurface");
if (eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &dummy) == EGL_TRUE) {
if (dummy == EGL_BUFFER_PRESERVED) {
@ -212,8 +214,6 @@ void DisplayHardware::init(uint32_t dpy)
*/
context = eglCreateContext(display, config, NULL, NULL);
//checkEGLErrors("eglCreateContext");
/*
* Gather OpenGL ES extensions

View File

@ -28,9 +28,9 @@
#include <ui/PixelFormat.h>
#include <ui/Surface.h>
#include "Buffer.h"
#include "clz.h"
#include "Layer.h"
#include "LayerBitmap.h"
#include "SurfaceFlinger.h"
#include "DisplayHardware/DisplayHardware.h"
@ -47,26 +47,29 @@ const char* const Layer::typeID = "Layer";
// ---------------------------------------------------------------------------
Layer::Layer(SurfaceFlinger* flinger, DisplayID display, const sp<Client>& c, int32_t i)
: LayerBaseClient(flinger, display, c, i),
Layer::Layer(SurfaceFlinger* flinger, DisplayID display,
const sp<Client>& c, int32_t i)
: LayerBaseClient(flinger, display, c, i), lcblk(NULL),
mSecure(false),
mFrontBufferIndex(1),
mNeedsBlending(true),
mResizeTransactionDone(false)
mNeedsBlending(true)
{
// no OpenGL operation is possible here, since we might not be
// in the OpenGL thread.
lcblk = new SharedBufferServer(c->ctrlblk, i, NUM_BUFFERS);
mFrontBufferIndex = lcblk->getFrontBuffer();
}
Layer::~Layer()
{
destroy();
// the actual buffers will be destroyed here
delete lcblk;
}
void Layer::destroy()
{
for (int i=0 ; i<NUM_BUFFERS ; i++) {
for (size_t i=0 ; i<NUM_BUFFERS ; i++) {
if (mTextures[i].name != -1U) {
glDeleteTextures(1, &mTextures[i].name);
mTextures[i].name = -1U;
@ -76,19 +79,11 @@ void Layer::destroy()
eglDestroyImageKHR(dpy, mTextures[i].image);
mTextures[i].image = EGL_NO_IMAGE_KHR;
}
mBuffers[i].free();
mBuffers[i].clear();
}
mSurface.clear();
}
void Layer::initStates(uint32_t w, uint32_t h, uint32_t flags)
{
LayerBase::initStates(w,h,flags);
if (flags & ISurfaceComposer::eDestroyBackbuffer)
lcblk->flags |= eNoCopyBack;
}
sp<LayerBaseClient::Surface> Layer::createSurface() const
{
return mSurface;
@ -112,13 +107,14 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h,
if (flags & ISurfaceComposer::eSecure)
bufferFlags |= Buffer::SECURE;
mFormat = format;
mWidth = w;
mHeight = h;
mSecure = (bufferFlags & Buffer::SECURE) ? true : false;
mNeedsBlending = (info.h_alpha - info.l_alpha) > 0;
for (int i=0 ; i<2 ; i++) {
err = mBuffers[i].init(lcblk->surface + i, w, h, format, bufferFlags);
if (err != NO_ERROR) {
return err;
}
mBufferFlags = bufferFlags;
for (size_t i=0 ; i<NUM_BUFFERS ; i++) {
mBuffers[i] = new Buffer();
}
mSurface = new SurfaceLayer(mFlinger, clientIndex(), this);
return NO_ERROR;
@ -126,7 +122,8 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h,
void Layer::reloadTexture(const Region& dirty)
{
const sp<Buffer>& buffer(frontBuffer().getBuffer());
Mutex::Autolock _l(mLock);
sp<Buffer> buffer(getFrontBuffer());
if (LIKELY(mFlags & DisplayHardware::DIRECT_TEXTURE)) {
int index = mFrontBufferIndex;
if (LIKELY(!mTextures[index].dirty)) {
@ -202,195 +199,113 @@ void Layer::onDraw(const Region& clip) const
const int index = (mFlags & DisplayHardware::DIRECT_TEXTURE) ?
mFrontBufferIndex : 0;
GLuint textureName = mTextures[index].name;
if (UNLIKELY(textureName == -1LU)) {
LOGW("Layer %p doesn't have a texture", this);
//LOGW("Layer %p doesn't have a texture", this);
// the texture has not been created yet, this Layer has
// in fact never been drawn into. this happens frequently with
// SurfaceView.
clearWithOpenGL(clip);
return;
}
drawWithOpenGL(clip, mTextures[index]);
}
sp<SurfaceBuffer> Layer::peekBuffer(int usage)
sp<SurfaceBuffer> Layer::requestBuffer(int index, int usage)
{
/*
* This is called from the client's Surface::lock(), after it locked
* the surface successfully. We're therefore guaranteed that the
* back-buffer is not in use by ourselves.
* Of course, we need to validate all this, which is not trivial.
*
* FIXME: A resize could happen at any time here. What to do about this?
* - resize() form post()
* - resize() from doTransaction()
*
* We'll probably need an internal lock for this.
*
* This is called from the client's Surface::dequeue(). This can happen
* at any time, especially while we're in the middle of using the
* buffer 'index' as our front buffer.
*
* TODO: We need to make sure that post() doesn't swap
* the buffers under us.
* Make sure the buffer we're resizing is not the front buffer and has been
* dequeued. Once this condition is asserted, we are guaranteed that this
* buffer cannot become the front buffer under our feet, since we're called
* from Surface::dequeue()
*/
status_t err = lcblk->assertReallocate(index);
LOGE_IF(err, "assertReallocate(%d) failed (%s)", index, strerror(-err));
// it's okay to read swapState for the purpose of figuring out the
// backbuffer index, which cannot change (since the app has locked it).
const uint32_t state = lcblk->swapState;
const int32_t backBufferIndex = layer_cblk_t::backBuffer(state);
Mutex::Autolock _l(mLock);
uint32_t w = mWidth;
uint32_t h = mHeight;
// get rid of the EGL image, since we shouldn't need it anymore
// (note that we're in a different thread than where it is being used)
if (mTextures[backBufferIndex].image != EGL_NO_IMAGE_KHR) {
EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
eglDestroyImageKHR(dpy, mTextures[backBufferIndex].image);
mTextures[backBufferIndex].image = EGL_NO_IMAGE_KHR;
}
LayerBitmap& layerBitmap(mBuffers[backBufferIndex]);
sp<SurfaceBuffer> buffer = layerBitmap.allocate(usage);
LOGD_IF(DEBUG_RESIZE,
"Layer::getBuffer(this=%p), index=%d, (%d,%d), (%d,%d)",
this, backBufferIndex,
layerBitmap.getWidth(),
layerBitmap.getHeight(),
layerBitmap.getBuffer()->getWidth(),
layerBitmap.getBuffer()->getHeight());
if (UNLIKELY(buffer == 0)) {
// XXX: what to do, what to do?
sp<Buffer>& buffer(mBuffers[index]);
if (buffer->getStrongCount() == 1) {
err = buffer->reallocate(w, h, mFormat, usage, mBufferFlags);
} else {
// here we have to reallocate a new buffer because we could have a
// client in our process with a reference to it (eg: status bar),
// and we can't release the handle under its feet.
buffer.clear();
buffer = new Buffer(w, h, mFormat, usage, mBufferFlags);
err = buffer->initCheck();
}
if (err || buffer->handle == 0) {
LOGE_IF(err || buffer->handle == 0,
"Layer::requestBuffer(this=%p), index=%d, w=%d, h=%d failed (%s)",
this, index, w, h, strerror(-err));
} else {
LOGD_IF(DEBUG_RESIZE,
"Layer::requestBuffer(this=%p), index=%d, w=%d, h=%d",
this, index, w, h);
}
if (err == NO_ERROR && buffer->handle != 0) {
// texture is now dirty...
mTextures[backBufferIndex].dirty = true;
// ... so it the visible region (because we consider the surface's
// buffer size for visibility calculations)
forceVisibilityTransaction();
mFlinger->setTransactionFlags(eTraversalNeeded);
mTextures[index].dirty = true;
}
return buffer;
}
void Layer::scheduleBroadcast()
{
sp<Client> ourClient(client.promote());
if (ourClient != 0) {
mFlinger->scheduleBroadcast(ourClient);
}
}
uint32_t Layer::doTransaction(uint32_t flags)
{
const Layer::State& front(drawingState());
const Layer::State& temp(currentState());
// the test front.{w|h} != temp.{w|h} is not enough because it is possible
// that the size changed back to its previous value before the buffer
// was resized (in the eLocked case below), in which case, we still
// need to execute the code below so the clients have a chance to be
// release. resize() deals with the fact that the size can be the same.
/*
* Various states we could be in...
resize = state & eResizeRequested;
if (backbufferChanged) {
if (resize == 0) {
// ERROR, the resized buffer doesn't have its resize flag set
} else if (resize == mask) {
// ERROR one of the buffer has already been resized
} else if (resize == mask ^ eResizeRequested) {
// ERROR, the resized buffer doesn't have its resize flag set
} else if (resize == eResizeRequested) {
// OK, Normal case, proceed with resize
}
} else {
if (resize == 0) {
// OK, nothing special, do nothing
} else if (resize == mask) {
// restarted transaction, do nothing
} else if (resize == mask ^ eResizeRequested) {
// restarted transaction, do nothing
} else if (resize == eResizeRequested) {
// OK, size reset to previous value, proceed with resize
}
}
*/
// Index of the back buffer
const bool backbufferChanged = (front.w != temp.w) || (front.h != temp.h);
const uint32_t state = lcblk->swapState;
const int32_t clientBackBufferIndex = layer_cblk_t::backBuffer(state);
const uint32_t mask = clientBackBufferIndex ? eResizeBuffer1 : eResizeBuffer0;
uint32_t resizeFlags = state & eResizeRequested;
if (UNLIKELY(backbufferChanged && (resizeFlags != eResizeRequested))) {
LOGE( "backbuffer size changed, but both resize flags are not set! "
"(layer=%p), state=%08x, requested (%dx%d), drawing (%d,%d), "
"index=%d, (%dx%d), (%dx%d)",
this, state,
int(temp.w), int(temp.h),
int(drawingState().w), int(drawingState().h),
int(clientBackBufferIndex),
int(mBuffers[0].getWidth()), int(mBuffers[0].getHeight()),
int(mBuffers[1].getWidth()), int(mBuffers[1].getHeight()));
// if we get there we're pretty screwed. the only reasonable
// thing to do is to pretend we should do the resize since
// backbufferChanged is set (this also will give a chance to
// client to get unblocked)
resizeFlags = eResizeRequested;
}
if (resizeFlags == eResizeRequested) {
// NOTE: asserting that clientBackBufferIndex!=mFrontBufferIndex
// here, would be wrong and misleading because by this point
// mFrontBufferIndex has not been updated yet.
if (backbufferChanged) {
// the size changed, we need to ask our client to request a new buffer
LOGD_IF(DEBUG_RESIZE,
"resize (layer=%p), state=%08x, "
"requested (%dx%d), "
"drawing (%d,%d), "
"index=%d, (%dx%d), (%dx%d)",
this, state,
int(temp.w), int(temp.h),
"resize (layer=%p), requested (%dx%d), "
"drawing (%d,%d), (%dx%d), (%dx%d)",
this, int(temp.w), int(temp.h),
int(drawingState().w), int(drawingState().h),
int(clientBackBufferIndex),
int(mBuffers[0].getWidth()), int(mBuffers[0].getHeight()),
int(mBuffers[1].getWidth()), int(mBuffers[1].getHeight()));
int(mBuffers[0]->getWidth()), int(mBuffers[0]->getHeight()),
int(mBuffers[1]->getWidth()), int(mBuffers[1]->getHeight()));
if (state & eLocked) {
// if the buffer is locked, we can't resize anything because
// - the backbuffer is currently in use by the user
// - the front buffer is being shown
// We just act as if the transaction didn't happen and we
// reschedule it later...
flags |= eRestartTransaction;
} else {
// This buffer needs to be resized
status_t err =
resize(clientBackBufferIndex, temp.w, temp.h, "transaction");
if (err == NO_ERROR) {
const uint32_t mask = clientBackBufferIndex ?
eResizeBuffer1 : eResizeBuffer0;
android_atomic_and(~mask, &(lcblk->swapState));
// since a buffer became available, we can let the client go...
scheduleBroadcast();
mResizeTransactionDone = true;
// record the new size, form this point on, when the client request a
// buffer, it'll get the new size.
setDrawingSize(temp.w, temp.h);
// we're being resized and there is a freeze display request,
// acquire a freeze lock, so that the screen stays put
// until we've redrawn at the new size; this is to avoid
// glitches upon orientation changes.
if (mFlinger->hasFreezeRequest()) {
// if the surface is hidden, don't try to acquire the
// freeze lock, since hidden surfaces may never redraw
if (!(front.flags & ISurfaceComposer::eLayerHidden)) {
mFreezeLock = mFlinger->getFreezeLock();
}
}
// all buffers need reallocation
lcblk->reallocate();
// recompute the visible region
// FIXME: ideally we would do that only when we have received
// a buffer of the right size
flags |= Layer::eVisibleRegion;
this->contentDirty = true;
#if 0
// FIXME: handle freeze lock
// we're being resized and there is a freeze display request,
// acquire a freeze lock, so that the screen stays put
// until we've redrawn at the new size; this is to avoid
// glitches upon orientation changes.
if (mFlinger->hasFreezeRequest()) {
// if the surface is hidden, don't try to acquire the
// freeze lock, since hidden surfaces may never redraw
if (!(front.flags & ISurfaceComposer::eLayerHidden)) {
mFreezeLock = mFlinger->getFreezeLock();
}
}
#endif
}
if (temp.sequence != front.sequence) {
if (temp.flags & ISurfaceComposer::eLayerHidden || temp.alpha == 0) {
// this surface is now hidden, so it shouldn't hold a freeze lock
@ -402,65 +317,10 @@ uint32_t Layer::doTransaction(uint32_t flags)
return LayerBase::doTransaction(flags);
}
status_t Layer::resize(
int32_t clientBackBufferIndex,
uint32_t width, uint32_t height,
const char* what)
{
/*
* handle resize (backbuffer and frontbuffer reallocation)
* this is called from post() or from doTransaction()
*/
const LayerBitmap& clientBackBuffer(mBuffers[clientBackBufferIndex]);
// if the new (transaction) size is != from the the backbuffer
// then we need to reallocate the backbuffer
bool backbufferChanged = (clientBackBuffer.getWidth() != width) ||
(clientBackBuffer.getHeight() != height);
LOGD_IF(!backbufferChanged,
"(%s) eResizeRequested (layer=%p), but size not changed: "
"requested (%dx%d), drawing (%d,%d), current (%d,%d),"
"state=%08lx, index=%d, (%dx%d), (%dx%d)",
what, this,
int(width), int(height),
int(drawingState().w), int(drawingState().h),
int(currentState().w), int(currentState().h),
long(lcblk->swapState),
int(clientBackBufferIndex),
int(mBuffers[0].getWidth()), int(mBuffers[0].getHeight()),
int(mBuffers[1].getWidth()), int(mBuffers[1].getHeight()));
// this can happen when changing the size back and forth quickly
status_t err = NO_ERROR;
if (backbufferChanged) {
LOGD_IF(DEBUG_RESIZE,
"resize (layer=%p), requested (%dx%d), "
"index=%d, (%dx%d), (%dx%d)",
this, int(width), int(height), int(clientBackBufferIndex),
int(mBuffers[0].getWidth()), int(mBuffers[0].getHeight()),
int(mBuffers[1].getWidth()), int(mBuffers[1].getHeight()));
err = mBuffers[clientBackBufferIndex].setSize(width, height);
if (UNLIKELY(err != NO_ERROR)) {
// This really should never happen
LOGE("resizing buffer %d to (%u,%u) failed [%08x] %s",
clientBackBufferIndex, width, height, err, strerror(err));
// couldn't reallocate the surface
android_atomic_write(eInvalidSurface, &lcblk->swapState);
}
}
return err;
}
void Layer::setSizeChanged(uint32_t w, uint32_t h)
{
LOGD_IF(DEBUG_RESIZE,
"setSizeChanged w=%d, h=%d (old: w=%d, h=%d)",
w, h, mCurrentState.w, mCurrentState.h);
android_atomic_or(eResizeRequested, &(lcblk->swapState));
void Layer::setDrawingSize(uint32_t w, uint32_t h) {
Mutex::Autolock _l(mLock);
mWidth = w;
mHeight = h;
}
// ----------------------------------------------------------------------------
@ -469,139 +329,26 @@ void Layer::setSizeChanged(uint32_t w, uint32_t h)
void Layer::lockPageFlip(bool& recomputeVisibleRegions)
{
uint32_t state = android_atomic_or(eBusy, &(lcblk->swapState));
// preemptively block the client, because he might set
// eFlipRequested at any time and want to use this buffer
// for the next frame. This will be unset below if it
// turns out we didn't need it.
uint32_t mask = eInvalidSurface | eFlipRequested | eResizeRequested;
if (!(state & mask))
return;
if (UNLIKELY(state & eInvalidSurface)) {
// if eInvalidSurface is set, this means the surface
// became invalid during a transaction (NO_MEMORY for instance)
scheduleBroadcast();
ssize_t buf = lcblk->retireAndLock();
if (buf < NO_ERROR) {
//LOGW("nothing to retire (%s)", strerror(-buf));
// NOTE: here the buffer is locked because we will used
// for composition later in the loop
return;
}
if (UNLIKELY(state & eFlipRequested)) {
uint32_t oldState;
mPostedDirtyRegion = post(&oldState, recomputeVisibleRegions);
if (oldState & eNextFlipPending) {
// Process another round (we know at least a buffer
// is ready for that client).
mFlinger->signalEvent();
}
}
}
Region Layer::post(uint32_t* previousSate, bool& recomputeVisibleRegions)
{
// atomically swap buffers and (re)set eFlipRequested
int32_t oldValue, newValue;
layer_cblk_t * const lcblk = this->lcblk;
do {
oldValue = lcblk->swapState;
// get the current value
LOG_ASSERT(oldValue&eFlipRequested,
"eFlipRequested not set, yet we're flipping! (state=0x%08lx)",
long(oldValue));
newValue = (oldValue ^ eIndex);
// swap buffers
newValue &= ~(eFlipRequested | eNextFlipPending);
// clear eFlipRequested and eNextFlipPending
if (oldValue & eNextFlipPending)
newValue |= eFlipRequested;
// if eNextFlipPending is set (second buffer already has something
// in it) we need to reset eFlipRequested because the client
// might never do it
} while(android_atomic_cmpxchg(oldValue, newValue, &(lcblk->swapState)));
*previousSate = oldValue;
const int32_t index = (newValue & eIndex) ^ 1;
mFrontBufferIndex = index;
// we retired a buffer, which becomes the new front buffer
mFrontBufferIndex = buf;
/* NOTE: it's safe to set this flag here because this is only touched
* from LayerBitmap::allocate(), which by construction cannot happen
* while we're in post().
*/
lcblk->surface[index].flags &= ~surface_info_t::eBufferDirty;
// get the dirty region
sp<Buffer> newFrontBuffer(getBuffer(buf));
const Region dirty(lcblk->getDirtyRegion(buf));
mPostedDirtyRegion = dirty.intersect( newFrontBuffer->getBounds() );
// ... post the new front-buffer
Region dirty(lcblk->region + index);
dirty.andSelf(frontBuffer().getBounds());
// FIXME: signal an event if we have more buffers waiting
// mFlinger->signalEvent();
//LOGD("Did post oldValue=%08lx, newValue=%08lx, mFrontBufferIndex=%u\n",
// oldValue, newValue, mFrontBufferIndex);
//dirty.dump("dirty");
if (UNLIKELY(oldValue & eResizeRequested)) {
LOGD_IF(DEBUG_RESIZE,
"post (layer=%p), state=%08x, "
"index=%d, (%dx%d), (%dx%d)",
this, newValue,
int(1-index),
int(mBuffers[0].getWidth()), int(mBuffers[0].getHeight()),
int(mBuffers[1].getWidth()), int(mBuffers[1].getHeight()));
// here, we just posted the surface and we have resolved
// the front/back buffer indices. The client is blocked, so
// it cannot start using the new backbuffer.
// If the backbuffer was resized in THIS round, we actually cannot
// resize the frontbuffer because it has *just* been drawn (and we
// would have nothing to draw). In this case we just skip the resize
// it'll happen after the next page flip or during the next
// transaction.
const uint32_t mask = (1-index) ? eResizeBuffer1 : eResizeBuffer0;
if (mResizeTransactionDone && (newValue & mask)) {
// Resize the layer's second buffer only if the transaction
// happened. It may not have happened yet if eResizeRequested
// was set immediately after the "transactionRequested" test,
// in which case the drawing state's size would be wrong.
mFreezeLock.clear();
const Layer::State& s(drawingState());
if (resize(1-index, s.w, s.h, "post") == NO_ERROR) {
do {
oldValue = lcblk->swapState;
if ((oldValue & eResizeRequested) == eResizeRequested) {
// ugh, another resize was requested since we processed
// the first buffer, don't free the client, and let
// the next transaction handle everything.
break;
}
newValue = oldValue & ~mask;
} while(android_atomic_cmpxchg(oldValue, newValue, &(lcblk->swapState)));
}
mResizeTransactionDone = false;
recomputeVisibleRegions = true;
this->contentDirty = true;
}
}
reloadTexture(dirty);
return dirty;
}
Point Layer::getPhysicalSize() const
{
sp<const Buffer> front(frontBuffer().getBuffer());
Point size(front->getWidth(), front->getHeight());
if ((size.x | size.y) == 0) {
// if we don't have a buffer yet, just use the state's size.
size = LayerBase::getPhysicalSize();
}
return size;
reloadTexture( mPostedDirtyRegion );
}
void Layer::unlockPageFlip(
@ -622,21 +369,15 @@ void Layer::unlockPageFlip(
// is in screen space as well).
dirtyRegion.andSelf(visibleRegionScreen);
outDirtyRegion.orSelf(dirtyRegion);
// client could be blocked, so signal them so they get a
// chance to reevaluate their condition.
scheduleBroadcast();
}
}
void Layer::finishPageFlip()
{
if (LIKELY(!(lcblk->swapState & eInvalidSurface))) {
LOGE_IF(!(lcblk->swapState & eBusy),
"layer %p wasn't locked!", this);
android_atomic_and(~eBusy, &(lcblk->swapState));
}
scheduleBroadcast();
status_t err = lcblk->unlock( mFrontBufferIndex );
LOGE_IF(err!=NO_ERROR,
"layer %p, buffer=%d wasn't locked!",
this, mFrontBufferIndex);
}
// ---------------------------------------------------------------------------
@ -651,12 +392,16 @@ Layer::SurfaceLayer::~SurfaceLayer()
{
}
sp<SurfaceBuffer> Layer::SurfaceLayer::getBuffer(int usage)
sp<SurfaceBuffer> Layer::SurfaceLayer::requestBuffer(int index, int usage)
{
sp<SurfaceBuffer> buffer = 0;
sp<SurfaceBuffer> buffer;
sp<Layer> owner(getOwner());
if (owner != 0) {
buffer = owner->peekBuffer(usage);
LOGE_IF(uint32_t(index)>=NUM_BUFFERS,
"getBuffer() index (%d) out of range", index);
if (uint32_t(index) < NUM_BUFFERS) {
buffer = owner->requestBuffer(index, usage);
}
}
return buffer;
}

View File

@ -21,10 +21,6 @@
#include <sys/types.h>
#include <ui/PixelFormat.h>
#include <private/ui/SharedState.h>
#include <private/ui/LayerState.h>
#include <pixelflinger/pixelflinger.h>
#include <EGL/egl.h>
@ -32,7 +28,7 @@
#include <GLES/gl.h>
#include <GLES/glext.h>
#include "LayerBitmap.h"
#include "Buffer.h"
#include "LayerBase.h"
#include "Transform.h"
@ -41,12 +37,12 @@ namespace android {
// ---------------------------------------------------------------------------
class Client;
class LayerBitmap;
class FreezeLock;
class Buffer;
// ---------------------------------------------------------------------------
const int NUM_BUFFERS = 2;
const size_t NUM_BUFFERS = 2;
class Layer : public LayerBaseClient
{
@ -56,23 +52,22 @@ public:
virtual char const* getTypeID() const { return typeID; }
virtual uint32_t getTypeInfo() const { return typeInfo; }
SharedBufferServer* lcblk;
Layer(SurfaceFlinger* flinger, DisplayID display,
const sp<Client>& client, int32_t i);
virtual ~Layer();
inline PixelFormat pixelFormat() const {
return frontBuffer().getPixelFormat();
}
status_t setBuffers(uint32_t w, uint32_t h,
PixelFormat format, uint32_t flags=0);
status_t setBuffers( uint32_t w, uint32_t h,
PixelFormat format, uint32_t flags=0);
void setDrawingSize(uint32_t w, uint32_t h);
virtual void onDraw(const Region& clip) const;
virtual void initStates(uint32_t w, uint32_t h, uint32_t flags);
virtual void setSizeChanged(uint32_t w, uint32_t h);
virtual uint32_t doTransaction(uint32_t transactionFlags);
virtual Point getPhysicalSize() const;
virtual void lockPageFlip(bool& recomputeVisibleRegions);
virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
virtual void finishPageFlip();
@ -80,42 +75,31 @@ public:
virtual bool isSecure() const { return mSecure; }
virtual sp<Surface> createSurface() const;
virtual status_t ditch();
const LayerBitmap& getBuffer(int i) const { return mBuffers[i]; }
LayerBitmap& getBuffer(int i) { return mBuffers[i]; }
// only for debugging
const sp<FreezeLock>& getFreezeLock() const { return mFreezeLock; }
inline sp<Buffer> getBuffer(int i) { return mBuffers[i]; }
// only for debugging
inline const sp<FreezeLock>& getFreezeLock() const { return mFreezeLock; }
// only for debugging
inline PixelFormat pixelFormat() const { return mFormat; }
private:
inline const LayerBitmap&
frontBuffer() const { return getBuffer(mFrontBufferIndex); }
inline LayerBitmap&
frontBuffer() { return getBuffer(mFrontBufferIndex); }
inline const LayerBitmap&
backBuffer() const { return getBuffer(1-mFrontBufferIndex); }
inline LayerBitmap&
backBuffer() { return getBuffer(1-mFrontBufferIndex); }
inline sp<Buffer> getFrontBuffer() {
return mBuffers[mFrontBufferIndex];
}
void reloadTexture(const Region& dirty);
status_t resize(int32_t index, uint32_t w, uint32_t h, const char* what);
Region post(uint32_t* oldState, bool& recomputeVisibleRegions);
sp<SurfaceBuffer> peekBuffer(int usage);
sp<SurfaceBuffer> requestBuffer(int index, int usage);
void destroy();
void scheduleBroadcast();
class SurfaceLayer : public LayerBaseClient::Surface
{
class SurfaceLayer : public LayerBaseClient::Surface {
public:
SurfaceLayer(const sp<SurfaceFlinger>& flinger,
SurfaceID id, const sp<Layer>& owner);
~SurfaceLayer();
SurfaceLayer(const sp<SurfaceFlinger>& flinger,
SurfaceID id, const sp<Layer>& owner);
~SurfaceLayer();
private:
virtual sp<SurfaceBuffer> getBuffer(int usage);
virtual sp<SurfaceBuffer> requestBuffer(int index, int usage);
sp<Layer> getOwner() const {
return static_cast<Layer*>(Surface::getOwner().get());
}
@ -125,13 +109,20 @@ private:
sp<Surface> mSurface;
bool mSecure;
LayerBitmap mBuffers[NUM_BUFFERS];
Texture mTextures[NUM_BUFFERS];
int32_t mFrontBufferIndex;
bool mNeedsBlending;
bool mResizeTransactionDone;
Region mPostedDirtyRegion;
sp<FreezeLock> mFreezeLock;
PixelFormat mFormat;
uint32_t mBufferFlags;
// protected by mLock
sp<Buffer> mBuffers[NUM_BUFFERS];
Texture mTextures[NUM_BUFFERS];
uint32_t mWidth;
uint32_t mHeight;
mutable Mutex mLock;
};
// ---------------------------------------------------------------------------

View File

@ -30,7 +30,6 @@
#include "clz.h"
#include "LayerBase.h"
#include "LayerBlur.h"
#include "SurfaceFlinger.h"
#include "DisplayHardware/DisplayHardware.h"
@ -127,9 +126,6 @@ uint32_t LayerBase::setTransactionFlags(uint32_t flags) {
return android_atomic_or(flags, &mTransactionFlags);
}
void LayerBase::setSizeChanged(uint32_t w, uint32_t h) {
}
bool LayerBase::setPosition(int32_t x, int32_t y) {
if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y)
return false;
@ -149,7 +145,6 @@ bool LayerBase::setLayer(uint32_t z) {
bool LayerBase::setSize(uint32_t w, uint32_t h) {
if (mCurrentState.w == w && mCurrentState.h == h)
return false;
setSizeChanged(w, h);
mCurrentState.w = w;
mCurrentState.h = h;
requestTransaction();
@ -219,21 +214,14 @@ uint32_t LayerBase::doTransaction(uint32_t flags)
return flags;
}
Point LayerBase::getPhysicalSize() const
{
const Layer::State& front(drawingState());
return Point(front.w, front.h);
}
void LayerBase::validateVisibility(const Transform& planeTransform)
{
const Layer::State& s(drawingState());
const Transform tr(planeTransform * s.transform);
const bool transformed = tr.transformed();
const Point size(getPhysicalSize());
uint32_t w = size.x;
uint32_t h = size.y;
uint32_t w = s.w;
uint32_t h = s.h;
tr.transform(mVertices[0], 0, 0);
tr.transform(mVertices[1], 0, h);
tr.transform(mVertices[2], w, h);
@ -655,9 +643,7 @@ int32_t LayerBaseClient::sIdentity = 0;
LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
const sp<Client>& client, int32_t i)
: LayerBase(flinger, display), client(client),
lcblk( client!=0 ? &(client->ctrlblk->layers[i]) : 0 ),
mIndex(i),
mIdentity(uint32_t(android_atomic_inc(&sIdentity)))
mIndex(i), mIdentity(uint32_t(android_atomic_inc(&sIdentity)))
{
}
@ -666,11 +652,8 @@ void LayerBaseClient::onFirstRef()
sp<Client> client(this->client.promote());
if (client != 0) {
client->bindLayer(this, mIndex);
// Initialize this layer's control block
memset(this->lcblk, 0, sizeof(layer_cblk_t));
this->lcblk->identity = mIdentity;
Region::writeEmpty(&(this->lcblk->region[0]), sizeof(flat_region_t));
Region::writeEmpty(&(this->lcblk->region[1]), sizeof(flat_region_t));
// Initialize this layer's identity
client->ctrlblk->setIdentity(mIndex, mIdentity);
}
}
@ -759,7 +742,7 @@ status_t LayerBaseClient::Surface::onTransact(
return BnSurface::onTransact(code, data, reply, flags);
}
sp<SurfaceBuffer> LayerBaseClient::Surface::getBuffer(int)
sp<SurfaceBuffer> LayerBaseClient::Surface::requestBuffer(int index, int usage)
{
return NULL;
}

View File

@ -23,6 +23,7 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <private/ui/SharedBufferStack.h>
#include <private/ui/LayerState.h>
#include <utils/RefBase.h>
@ -136,11 +137,6 @@ public:
*/
virtual void initStates(uint32_t w, uint32_t h, uint32_t flags);
/**
* setSizeChanged - called when the *current* state's size is changed.
*/
virtual void setSizeChanged(uint32_t w, uint32_t h);
/**
* doTransaction - process the transaction. This is a good place to figure
* out which attributes of the surface have changed.
@ -160,13 +156,6 @@ public:
*/
virtual void setCoveredRegion(const Region& coveredRegion);
/**
* getPhysicalSize - returns the physical size of the drawing state of
* the surface. If the surface is backed by a bitmap, this is the size of
* the bitmap (as opposed to the size of the drawing state).
*/
virtual Point getPhysicalSize() const;
/**
* validateVisibility - cache a bunch of things
*/
@ -308,8 +297,8 @@ public:
virtual ~LayerBaseClient();
virtual void onFirstRef();
wp<Client> client;
layer_cblk_t* const lcblk;
wp<Client> client;
// SharedBufferServer* lcblk;
inline uint32_t getIdentity() const { return mIdentity; }
inline int32_t clientIndex() const { return mIndex; }
@ -336,7 +325,7 @@ public:
sp<LayerBaseClient> getOwner() const;
private:
virtual sp<SurfaceBuffer> getBuffer(int usage);
virtual sp<SurfaceBuffer> requestBuffer(int index, int usage);
virtual status_t registerBuffers(const ISurface::BufferHeap& buffers);
virtual void postBuffer(ssize_t offset);
virtual void unregisterBuffers();

View File

@ -28,6 +28,7 @@
#include <hardware/copybit.h>
#include "Buffer.h"
#include "BufferAllocator.h"
#include "LayerBuffer.h"
#include "SurfaceFlinger.h"
@ -58,7 +59,7 @@ LayerBuffer::~LayerBuffer()
void LayerBuffer::onFirstRef()
{
LayerBaseClient::onFirstRef();
mSurface = new SurfaceBuffer(mFlinger, clientIndex(),
mSurface = new SurfaceLayerBuffer(mFlinger, clientIndex(),
const_cast<LayerBuffer *>(this));
}
@ -181,21 +182,21 @@ sp<LayerBuffer::Source> LayerBuffer::clearSource() {
}
// ============================================================================
// LayerBuffer::SurfaceBuffer
// LayerBuffer::SurfaceLayerBuffer
// ============================================================================
LayerBuffer::SurfaceBuffer::SurfaceBuffer(const sp<SurfaceFlinger>& flinger,
LayerBuffer::SurfaceLayerBuffer::SurfaceLayerBuffer(const sp<SurfaceFlinger>& flinger,
SurfaceID id, const sp<LayerBuffer>& owner)
: LayerBaseClient::Surface(flinger, id, owner->getIdentity(), owner)
{
}
LayerBuffer::SurfaceBuffer::~SurfaceBuffer()
LayerBuffer::SurfaceLayerBuffer::~SurfaceLayerBuffer()
{
unregisterBuffers();
}
status_t LayerBuffer::SurfaceBuffer::registerBuffers(
status_t LayerBuffer::SurfaceLayerBuffer::registerBuffers(
const ISurface::BufferHeap& buffers)
{
sp<LayerBuffer> owner(getOwner());
@ -204,21 +205,21 @@ status_t LayerBuffer::SurfaceBuffer::registerBuffers(
return NO_INIT;
}
void LayerBuffer::SurfaceBuffer::postBuffer(ssize_t offset)
void LayerBuffer::SurfaceLayerBuffer::postBuffer(ssize_t offset)
{
sp<LayerBuffer> owner(getOwner());
if (owner != 0)
owner->postBuffer(offset);
}
void LayerBuffer::SurfaceBuffer::unregisterBuffers()
void LayerBuffer::SurfaceLayerBuffer::unregisterBuffers()
{
sp<LayerBuffer> owner(getOwner());
if (owner != 0)
owner->unregisterBuffers();
}
sp<OverlayRef> LayerBuffer::SurfaceBuffer::createOverlay(
sp<OverlayRef> LayerBuffer::SurfaceLayerBuffer::createOverlay(
uint32_t w, uint32_t h, int32_t format) {
sp<OverlayRef> result;
sp<LayerBuffer> owner(getOwner());
@ -462,8 +463,8 @@ void LayerBuffer::BufferSource::onDraw(const Region& clip) const
const int tmp_h = floorf(src_height * yscale);
if (mTempBitmap==0 ||
mTempBitmap->getWidth() < tmp_w ||
mTempBitmap->getHeight() < tmp_h) {
mTempBitmap->getWidth() < size_t(tmp_w) ||
mTempBitmap->getHeight() < size_t(tmp_h)) {
mTempBitmap.clear();
mTempBitmap = new android::Buffer(
tmp_w, tmp_h, src.img.format,

View File

@ -24,7 +24,6 @@
#include <private/ui/LayerState.h>
#include "LayerBase.h"
#include "LayerBitmap.h"
struct copybit_device_t;
@ -32,9 +31,12 @@ namespace android {
// ---------------------------------------------------------------------------
class Buffer;
class Region;
class OverlayRef;
// ---------------------------------------------------------------------------
class LayerBuffer : public LayerBaseClient
{
class Source : public LightRefBase<Source> {
@ -179,12 +181,12 @@ private:
};
class SurfaceBuffer : public LayerBaseClient::Surface
class SurfaceLayerBuffer : public LayerBaseClient::Surface
{
public:
SurfaceBuffer(const sp<SurfaceFlinger>& flinger,
SurfaceLayerBuffer(const sp<SurfaceFlinger>& flinger,
SurfaceID id, const sp<LayerBuffer>& owner);
virtual ~SurfaceBuffer();
virtual ~SurfaceLayerBuffer();
virtual status_t registerBuffers(const ISurface::BufferHeap& buffers);
virtual void postBuffer(ssize_t offset);

View File

@ -21,6 +21,7 @@
#include <utils/Errors.h>
#include <utils/Log.h>
#include "Buffer.h"
#include "BufferAllocator.h"
#include "LayerDim.h"
#include "SurfaceFlinger.h"

View File

@ -24,12 +24,11 @@
#include <EGL/eglext.h>
#include "LayerBase.h"
#include "LayerBitmap.h"
namespace android {
// ---------------------------------------------------------------------------
namespace android {
class LayerDim : public LayerBaseClient
{
static bool sUseTexture;

View File

@ -44,12 +44,12 @@
#include <GLES/gl.h>
#include "clz.h"
#include "Buffer.h"
#include "BufferAllocator.h"
#include "Layer.h"
#include "LayerBlur.h"
#include "LayerBuffer.h"
#include "LayerDim.h"
#include "LayerBitmap.h"
#include "SurfaceFlinger.h"
#include "DisplayHardware/DisplayHardware.h"
@ -173,12 +173,12 @@ SurfaceFlinger::SurfaceFlinger()
: BnSurfaceComposer(), Thread(false),
mTransactionFlags(0),
mTransactionCount(0),
mResizeTransationPending(false),
mLayersRemoved(false),
mBootTime(systemTime()),
mHardwareTest("android.permission.HARDWARE_TEST"),
mAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"),
mDump("android.permission.DUMP"),
mLastScheduledBroadcast(NULL),
mVisibleRegionsDirty(false),
mDeferReleaseConsole(false),
mFreezeDisplay(false),
@ -497,13 +497,11 @@ bool SurfaceFlinger::threadLoop()
// release the clients before we flip ('cause flip might block)
unlockClients();
executeScheduledBroadcasts();
postFramebuffer();
} else {
// pretend we did the post
unlockClients();
executeScheduledBroadcasts();
usleep(16667); // 60 fps period
}
return true;
@ -773,7 +771,8 @@ void SurfaceFlinger::computeVisibleRegions(
void SurfaceFlinger::commitTransaction()
{
mDrawingState = mCurrentState;
mTransactionCV.signal();
mResizeTransationPending = false;
mTransactionCV.broadcast();
}
void SurfaceFlinger::handlePageFlip()
@ -910,37 +909,6 @@ void SurfaceFlinger::unlockClients()
}
}
void SurfaceFlinger::scheduleBroadcast(const sp<Client>& client)
{
if (mLastScheduledBroadcast != client) {
mLastScheduledBroadcast = client;
mScheduledBroadcasts.add(client);
}
}
void SurfaceFlinger::executeScheduledBroadcasts()
{
SortedVector< wp<Client> >& list(mScheduledBroadcasts);
size_t count = list.size();
while (count--) {
sp<Client> client = list[count].promote();
if (client != 0) {
per_client_cblk_t* const cblk = client->ctrlblk;
if (cblk->lock.tryLock() == NO_ERROR) {
cblk->cv.broadcast();
list.removeAt(count);
cblk->lock.unlock();
} else {
// schedule another round
LOGW("executeScheduledBroadcasts() skipped, "
"contention on the client. We'll try again later...");
signalDelayedEvent(ms2ns(4));
}
}
}
mLastScheduledBroadcast = 0;
}
void SurfaceFlinger::debugFlashRegions()
{
const DisplayHardware& hw(graphicPlane(0).displayHardware());
@ -1129,18 +1097,10 @@ void SurfaceFlinger::free_resources_l()
mLayersRemoved = false;
// free resources associated with disconnected clients
SortedVector< wp<Client> >& scheduledBroadcasts(mScheduledBroadcasts);
Vector< sp<Client> >& disconnectedClients(mDisconnectedClients);
const size_t count = disconnectedClients.size();
for (size_t i=0 ; i<count ; i++) {
sp<Client> client = disconnectedClients[i];
// if this client is the scheduled broadcast list,
// remove it from there (and we don't need to signal it
// since it is dead).
int32_t index = scheduledBroadcasts.indexOf(client);
if (index >= 0) {
scheduledBroadcasts.removeItemsAt(index);
}
mTokens.release(client->cid);
}
disconnectedClients.clear();
@ -1173,6 +1133,13 @@ void SurfaceFlinger::closeGlobalTransaction()
{
if (android_atomic_dec(&mTransactionCount) == 1) {
signalEvent();
// if there is a transaction with a resize, wait for it to
// take effect before returning.
Mutex::Autolock _l(mStateLock);
while (mResizeTransationPending) {
mTransactionCV.wait(mStateLock);
}
}
}
@ -1424,8 +1391,10 @@ status_t SurfaceFlinger::setClientState(
}
}
if (what & eSizeChanged) {
if (layer->setSize(s.w, s.h))
if (layer->setSize(s.w, s.h)) {
flags |= eTraversalNeeded;
mResizeTransationPending = true;
}
}
if (what & eAlphaChanged) {
if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f)))
@ -1543,28 +1512,27 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
"id=0x%08x, client=0x%08x, identity=%u\n",
lbc->clientIndex(), client.get() ? client->cid : 0,
lbc->getIdentity());
result.append(buffer);
buffer[0] = 0;
}
result.append(buffer);
buffer[0] = 0;
/*** Layer ***/
sp<Layer> l = LayerBase::dynamicCast< Layer* >(layer.get());
if (l != 0) {
const LayerBitmap& buf0(l->getBuffer(0));
const LayerBitmap& buf1(l->getBuffer(1));
result.append( l->lcblk->dump(" ") );
sp<const Buffer> buf0(l->getBuffer(0));
sp<const Buffer> buf1(l->getBuffer(1));
snprintf(buffer, SIZE,
" "
"format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u],"
" freezeLock=%p, swapState=0x%08x\n",
" freezeLock=%p\n",
l->pixelFormat(),
buf0.getWidth(), buf0.getHeight(),
buf0.getBuffer()->getStride(),
buf1.getWidth(), buf1.getHeight(),
buf1.getBuffer()->getStride(),
l->getFreezeLock().get(),
l->lcblk->swapState);
buf0->getWidth(), buf0->getHeight(), buf0->getStride(),
buf1->getWidth(), buf1->getHeight(), buf1->getStride(),
l->getFreezeLock().get());
result.append(buffer);
buffer[0] = 0;
}
result.append(buffer);
buffer[0] = 0;
s.transparentRegion.dump(result, "transparentRegion");
layer->transparentRegionScreen.dump(result, "transparentRegionScreen");
layer->visibleRegionScreen.dump(result, "visibleRegionScreen");
@ -1657,8 +1625,12 @@ status_t SurfaceFlinger::onTransact(
const DisplayHardware& hw(graphicPlane(0).displayHardware());
mDirtyRegion.set(hw.bounds()); // careful that's not thread-safe
signalEvent();
return NO_ERROR;
}
case 1005:{ // force transaction
setTransactionFlags(eTransactionNeeded|eTraversalNeeded);
return NO_ERROR;
}
return NO_ERROR;
case 1007: // set mFreezeCount
mFreezeCount = data.readInt32();
return NO_ERROR;
@ -1688,21 +1660,20 @@ Client::Client(ClientID clientID, const sp<SurfaceFlinger>& flinger)
: ctrlblk(0), cid(clientID), mPid(0), mBitmap(0), mFlinger(flinger)
{
const int pgsize = getpagesize();
const int cblksize = ((sizeof(per_client_cblk_t)+(pgsize-1))&~(pgsize-1));
const int cblksize = ((sizeof(SharedClient)+(pgsize-1))&~(pgsize-1));
mCblkHeap = new MemoryHeapBase(cblksize, 0,
"SurfaceFlinger Client control-block");
ctrlblk = static_cast<per_client_cblk_t *>(mCblkHeap->getBase());
ctrlblk = static_cast<SharedClient *>(mCblkHeap->getBase());
if (ctrlblk) { // construct the shared structure in-place.
new(ctrlblk) per_client_cblk_t;
new(ctrlblk) SharedClient;
}
}
Client::~Client() {
if (ctrlblk) {
const int pgsize = getpagesize();
ctrlblk->~per_client_cblk_t(); // destroy our shared-structure.
ctrlblk->~SharedClient(); // destroy our shared-structure.
}
}

View File

@ -34,7 +34,7 @@
#include <ui/ISurfaceComposer.h>
#include <ui/ISurfaceFlingerClient.h>
#include <private/ui/SharedState.h>
#include <private/ui/SharedBufferStack.h>
#include <private/ui/LayerState.h>
#include "Barrier.h"
@ -87,7 +87,7 @@ public:
}
// pointer to this client's control block
per_client_cblk_t* ctrlblk;
SharedClient* ctrlblk;
ClientID cid;
@ -268,8 +268,6 @@ private:
bool lockPageFlip(const LayerVector& currentLayers);
void unlockPageFlip(const LayerVector& currentLayers);
void handleRepaint();
void scheduleBroadcast(const sp<Client>& client);
void executeScheduledBroadcasts();
void postFramebuffer();
void composeSurfaces(const Region& dirty);
void unlockClients();
@ -313,6 +311,7 @@ private:
volatile int32_t mTransactionFlags;
volatile int32_t mTransactionCount;
Condition mTransactionCV;
bool mResizeTransationPending;
// protected by mStateLock (but we could use another lock)
Tokenizer mTokens;
@ -337,8 +336,6 @@ private:
Region mDirtyRegionRemovedLayer;
Region mInvalidRegion;
Region mWormholeRegion;
wp<Client> mLastScheduledBroadcast;
SortedVector< wp<Client> > mScheduledBroadcasts;
bool mVisibleRegionsDirty;
bool mDeferReleaseConsole;
bool mFreezeDisplay;

View File

@ -1,585 +0,0 @@
/*
* Copyright (C) 2008 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 "SurfaceFlinger"
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <cutils/log.h>
#include <cutils/properties.h>
#include <binder/IBinder.h>
#include <binder/MemoryDealer.h>
#include <binder/MemoryBase.h>
#include <binder/MemoryHeapPmem.h>
#include <binder/MemoryHeapBase.h>
#include <binder/IPCThreadState.h>
#include <utils/StopWatch.h>
#include <ui/ISurfaceComposer.h>
#include "VRamHeap.h"
#include "GPUHardware.h"
#if HAVE_ANDROID_OS
#include <linux/android_pmem.h>
#endif
#include "GPUHardware/GPUHardware.h"
/*
* Manage the GPU. This implementation is very specific to the G1.
* There are no abstraction here.
*
* All this code will soon go-away and be replaced by a new architecture
* for managing graphics accelerators.
*
* In the meantime, it is conceptually possible to instantiate a
* GPUHardwareInterface for another GPU (see GPUFactory at the bottom
* of this file); practically... doubtful.
*
*/
namespace android {
// ---------------------------------------------------------------------------
class GPUClientHeap;
class GPUAreaHeap;
class GPUHardware : public GPUHardwareInterface, public IBinder::DeathRecipient
{
public:
static const int GPU_RESERVED_SIZE;
static const int GPUR_SIZE;
GPUHardware();
virtual ~GPUHardware();
virtual void revoke(int pid);
virtual sp<MemoryDealer> request(int pid);
virtual status_t request(int pid,
const sp<IGPUCallback>& callback,
ISurfaceComposer::gpu_info_t* gpu);
virtual status_t friendlyRevoke();
virtual void unconditionalRevoke();
virtual pid_t getOwner() const { return mOwner; }
// used for debugging only...
virtual sp<SimpleBestFitAllocator> getAllocator() const;
private:
enum {
NO_OWNER = -1,
};
struct GPUArea {
sp<GPUAreaHeap> heap;
sp<MemoryHeapPmem> clientHeap;
sp<IMemory> map();
};
struct Client {
pid_t pid;
GPUArea smi;
GPUArea ebi;
GPUArea reg;
void createClientHeaps();
void revokeAllHeaps();
};
Client& getClientLocked(pid_t pid);
status_t requestLocked(int pid);
void releaseLocked();
void takeBackGPULocked();
void registerCallbackLocked(const sp<IGPUCallback>& callback,
Client& client);
virtual void binderDied(const wp<IBinder>& who);
mutable Mutex mLock;
sp<GPUAreaHeap> mSMIHeap;
sp<GPUAreaHeap> mEBIHeap;
sp<GPUAreaHeap> mREGHeap;
KeyedVector<pid_t, Client> mClients;
DefaultKeyedVector< wp<IBinder>, pid_t > mRegisteredClients;
pid_t mOwner;
sp<MemoryDealer> mCurrentAllocator;
sp<IGPUCallback> mCallback;
sp<SimpleBestFitAllocator> mAllocator;
Condition mCondition;
};
// size reserved for GPU surfaces
// 1200 KB fits exactly:
// - two 320*480 16-bits double-buffered surfaces
// - one 320*480 32-bits double-buffered surface
// - one 320*240 16-bits double-buffered, 4x anti-aliased surface
const int GPUHardware::GPU_RESERVED_SIZE = 1200 * 1024;
const int GPUHardware::GPUR_SIZE = 1 * 1024 * 1024;
// ---------------------------------------------------------------------------
/*
* GPUHandle is a special IMemory given to the client. It represents their
* handle to the GPU. Once they give it up, they loose GPU access, or if
* they explicitly revoke their access through the binder code 1000.
* In both cases, this triggers a callback to revoke()
* first, and then actually powers down the chip.
*
* In the case of a misbehaving app, GPUHardware can ask for an immediate
* release of the GPU to the target process which should answer by calling
* code 1000 on GPUHandle. If it doesn't in a timely manner, the GPU will
* be revoked from under their feet.
*
* We should never hold a strong reference on GPUHandle. In practice this
* shouldn't be a big issue though because clients should use code 1000 and
* not rely on the dtor being called.
*
*/
class GPUClientHeap : public MemoryHeapPmem
{
public:
GPUClientHeap(const wp<GPUHardware>& gpu,
const sp<MemoryHeapBase>& heap)
: MemoryHeapPmem(heap), mGPU(gpu) { }
protected:
wp<GPUHardware> mGPU;
};
class GPUAreaHeap : public MemoryHeapBase
{
public:
GPUAreaHeap(const wp<GPUHardware>& gpu,
const char* const vram, size_t size=0, size_t reserved=0)
: MemoryHeapBase(vram, size), mGPU(gpu) {
if (base() != MAP_FAILED) {
if (reserved == 0)
reserved = virtualSize();
mAllocator = new SimpleBestFitAllocator(reserved);
}
}
virtual sp<MemoryHeapPmem> createClientHeap() {
sp<MemoryHeapBase> parentHeap(this);
return new GPUClientHeap(mGPU, parentHeap);
}
virtual const sp<SimpleBestFitAllocator>& getAllocator() const {
return mAllocator;
}
private:
sp<SimpleBestFitAllocator> mAllocator;
protected:
wp<GPUHardware> mGPU;
};
class GPURegisterHeap : public GPUAreaHeap
{
public:
GPURegisterHeap(const sp<GPUHardware>& gpu)
: GPUAreaHeap(gpu, "/dev/hw3d", GPUHardware::GPUR_SIZE) { }
virtual sp<MemoryHeapPmem> createClientHeap() {
sp<MemoryHeapBase> parentHeap(this);
return new MemoryHeapRegs(mGPU, parentHeap);
}
private:
class MemoryHeapRegs : public GPUClientHeap {
public:
MemoryHeapRegs(const wp<GPUHardware>& gpu,
const sp<MemoryHeapBase>& heap)
: GPUClientHeap(gpu, heap) { }
sp<MemoryHeapPmem::MemoryPmem> createMemory(size_t offset, size_t size);
virtual void revoke();
private:
class GPUHandle : public MemoryHeapPmem::MemoryPmem {
public:
GPUHandle(const sp<GPUHardware>& gpu,
const sp<MemoryHeapPmem>& heap)
: MemoryHeapPmem::MemoryPmem(heap),
mGPU(gpu), mOwner(gpu->getOwner()) { }
virtual ~GPUHandle();
virtual sp<IMemoryHeap> getMemory(
ssize_t* offset, size_t* size) const;
virtual void revoke() { };
virtual status_t onTransact(
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags);
private:
void revokeNotification();
wp<GPUHardware> mGPU;
pid_t mOwner;
};
};
};
GPURegisterHeap::MemoryHeapRegs::GPUHandle::~GPUHandle() {
//LOGD("GPUHandle %p released, revoking GPU", this);
revokeNotification();
}
void GPURegisterHeap::MemoryHeapRegs::GPUHandle::revokeNotification() {
sp<GPUHardware> hw(mGPU.promote());
if (hw != 0) {
hw->revoke(mOwner);
}
}
sp<IMemoryHeap> GPURegisterHeap::MemoryHeapRegs::GPUHandle::getMemory(
ssize_t* offset, size_t* size) const
{
sp<MemoryHeapPmem> heap = getHeap();
if (offset) *offset = 0;
if (size) *size = heap !=0 ? heap->virtualSize() : 0;
return heap;
}
status_t GPURegisterHeap::MemoryHeapRegs::GPUHandle::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
status_t err = BnMemory::onTransact(code, data, reply, flags);
if (err == UNKNOWN_TRANSACTION && code == 1000) {
int callingPid = IPCThreadState::self()->getCallingPid();
//LOGD("pid %d voluntarily revoking gpu", callingPid);
if (callingPid == mOwner) {
revokeNotification();
// we've revoked the GPU, don't do it again later when we
// are destroyed.
mGPU.clear();
} else {
LOGW("%d revoking someone else's gpu? (owner=%d)",
callingPid, mOwner);
}
err = NO_ERROR;
}
return err;
}
// ---------------------------------------------------------------------------
sp<MemoryHeapPmem::MemoryPmem> GPURegisterHeap::MemoryHeapRegs::createMemory(
size_t offset, size_t size)
{
sp<GPUHandle> memory;
sp<GPUHardware> gpu = mGPU.promote();
if (heapID()>0 && gpu!=0) {
#if HAVE_ANDROID_OS
/* this is where the GPU is powered on and the registers are mapped
* in the client */
//LOGD("ioctl(HW3D_GRANT_GPU)");
int err = ioctl(heapID(), HW3D_GRANT_GPU, base());
if (err) {
// it can happen if the master heap has been closed already
// in which case the GPU already is revoked (app crash for
// instance).
LOGW("HW3D_GRANT_GPU failed (%s), mFD=%d, base=%p",
strerror(errno), heapID(), base());
}
memory = new GPUHandle(gpu, this);
#endif
}
return memory;
}
void GPURegisterHeap::MemoryHeapRegs::revoke()
{
MemoryHeapPmem::revoke();
#if HAVE_ANDROID_OS
if (heapID() > 0) {
//LOGD("ioctl(HW3D_REVOKE_GPU)");
int err = ioctl(heapID(), HW3D_REVOKE_GPU, base());
LOGE_IF(err, "HW3D_REVOKE_GPU failed (%s), mFD=%d, base=%p",
strerror(errno), heapID(), base());
}
#endif
}
/*****************************************************************************/
GPUHardware::GPUHardware()
: mOwner(NO_OWNER)
{
}
GPUHardware::~GPUHardware()
{
}
status_t GPUHardware::requestLocked(int pid)
{
const int self_pid = getpid();
if (pid == self_pid) {
// can't use GPU from surfaceflinger's process
return PERMISSION_DENIED;
}
if (mOwner != pid) {
if (mREGHeap != 0) {
if (mOwner != NO_OWNER) {
// someone already has the gpu.
takeBackGPULocked();
releaseLocked();
}
} else {
// first time, initialize the stuff.
if (mSMIHeap == 0)
mSMIHeap = new GPUAreaHeap(this, "/dev/pmem_gpu0");
if (mEBIHeap == 0)
mEBIHeap = new GPUAreaHeap(this,
"/dev/pmem_gpu1", 0, GPU_RESERVED_SIZE);
mREGHeap = new GPURegisterHeap(this);
mAllocator = mEBIHeap->getAllocator();
if (mAllocator == NULL) {
// something went terribly wrong.
mSMIHeap.clear();
mEBIHeap.clear();
mREGHeap.clear();
return INVALID_OPERATION;
}
}
Client& client = getClientLocked(pid);
mCurrentAllocator = new MemoryDealer(client.ebi.clientHeap, mAllocator);
mOwner = pid;
}
return NO_ERROR;
}
sp<MemoryDealer> GPUHardware::request(int pid)
{
sp<MemoryDealer> dealer;
Mutex::Autolock _l(mLock);
Client* client;
LOGD("pid %d requesting gpu surface (current owner = %d)", pid, mOwner);
if (requestLocked(pid) == NO_ERROR) {
dealer = mCurrentAllocator;
LOGD_IF(dealer!=0, "gpu surface granted to pid %d", mOwner);
}
return dealer;
}
status_t GPUHardware::request(int pid, const sp<IGPUCallback>& callback,
ISurfaceComposer::gpu_info_t* gpu)
{
if (callback == 0)
return BAD_VALUE;
sp<IMemory> gpuHandle;
LOGD("pid %d requesting gpu core (owner = %d)", pid, mOwner);
Mutex::Autolock _l(mLock);
status_t err = requestLocked(pid);
if (err == NO_ERROR) {
// it's guaranteed to be there, be construction
Client& client = mClients.editValueFor(pid);
registerCallbackLocked(callback, client);
gpu->count = 2;
gpu->regions[0].region = client.smi.map();
gpu->regions[1].region = client.ebi.map();
gpu->regs = client.reg.map();
gpu->regions[0].reserved = 0;
gpu->regions[1].reserved = GPU_RESERVED_SIZE;
if (gpu->regs != 0) {
//LOGD("gpu core granted to pid %d, handle base=%p",
// mOwner, gpu->regs->pointer());
}
mCallback = callback;
} else {
LOGW("couldn't grant gpu core to pid %d", pid);
}
return err;
}
void GPUHardware::revoke(int pid)
{
Mutex::Autolock _l(mLock);
if (mOwner > 0) {
if (pid != mOwner) {
LOGW("GPU owned by %d, revoke from %d", mOwner, pid);
return;
}
//LOGD("revoke pid=%d, owner=%d", pid, mOwner);
// mOwner could be <0 if the same process acquired the GPU
// several times without releasing it first.
mCondition.signal();
releaseLocked();
}
}
status_t GPUHardware::friendlyRevoke()
{
Mutex::Autolock _l(mLock);
//LOGD("friendlyRevoke owner=%d", mOwner);
takeBackGPULocked();
releaseLocked();
return NO_ERROR;
}
void GPUHardware::takeBackGPULocked()
{
sp<IGPUCallback> callback = mCallback;
mCallback.clear();
if (callback != 0) {
callback->gpuLost(); // one-way
mCondition.waitRelative(mLock, ms2ns(250));
}
}
void GPUHardware::releaseLocked()
{
//LOGD("revoking gpu from pid %d", mOwner);
if (mOwner != NO_OWNER) {
// this may fail because the client might have died, and have
// been removed from the list.
ssize_t index = mClients.indexOfKey(mOwner);
if (index >= 0) {
Client& client(mClients.editValueAt(index));
client.revokeAllHeaps();
}
mOwner = NO_OWNER;
mCurrentAllocator.clear();
mCallback.clear();
}
}
GPUHardware::Client& GPUHardware::getClientLocked(pid_t pid)
{
ssize_t index = mClients.indexOfKey(pid);
if (index < 0) {
Client client;
client.pid = pid;
client.smi.heap = mSMIHeap;
client.ebi.heap = mEBIHeap;
client.reg.heap = mREGHeap;
index = mClients.add(pid, client);
}
Client& client(mClients.editValueAt(index));
client.createClientHeaps();
return client;
}
// ----------------------------------------------------------------------------
// for debugging / testing ...
sp<SimpleBestFitAllocator> GPUHardware::getAllocator() const {
Mutex::Autolock _l(mLock);
return mAllocator;
}
void GPUHardware::unconditionalRevoke()
{
Mutex::Autolock _l(mLock);
releaseLocked();
}
// ---------------------------------------------------------------------------
sp<IMemory> GPUHardware::GPUArea::map() {
sp<IMemory> memory;
if (clientHeap != 0 && heap != 0) {
memory = clientHeap->mapMemory(0, heap->virtualSize());
}
return memory;
}
void GPUHardware::Client::createClientHeaps()
{
if (smi.clientHeap == 0)
smi.clientHeap = smi.heap->createClientHeap();
if (ebi.clientHeap == 0)
ebi.clientHeap = ebi.heap->createClientHeap();
if (reg.clientHeap == 0)
reg.clientHeap = reg.heap->createClientHeap();
}
void GPUHardware::Client::revokeAllHeaps()
{
if (smi.clientHeap != 0)
smi.clientHeap->revoke();
if (ebi.clientHeap != 0)
ebi.clientHeap->revoke();
if (reg.clientHeap != 0)
reg.clientHeap->revoke();
}
void GPUHardware::registerCallbackLocked(const sp<IGPUCallback>& callback,
Client& client)
{
sp<IBinder> binder = callback->asBinder();
if (mRegisteredClients.add(binder, client.pid) >= 0) {
binder->linkToDeath(this);
}
}
void GPUHardware::binderDied(const wp<IBinder>& who)
{
Mutex::Autolock _l(mLock);
pid_t pid = mRegisteredClients.valueFor(who);
if (pid != 0) {
ssize_t index = mClients.indexOfKey(pid);
if (index >= 0) {
//LOGD("*** removing client at %d", index);
Client& client(mClients.editValueAt(index));
client.revokeAllHeaps(); // not really needed in theory
mClients.removeItemsAt(index);
if (mClients.size() == 0) {
//LOGD("*** was last client closing everything");
mCallback.clear();
mAllocator.clear();
mCurrentAllocator.clear();
mSMIHeap.clear();
mREGHeap.clear();
// NOTE: we cannot clear the EBI heap because surfaceflinger
// itself may be using it, since this is where surfaces
// are allocated. if we're in the middle of compositing
// a surface (even if its process just died), we cannot
// rip the heap under our feet.
mOwner = NO_OWNER;
}
}
}
}
// ---------------------------------------------------------------------------
sp<GPUHardwareInterface> GPUFactory::getGPU()
{
sp<GPUHardwareInterface> gpu;
if (access("/dev/hw3d", F_OK) == 0) {
gpu = new GPUHardware();
}
return gpu;
}
// ---------------------------------------------------------------------------
}; // namespace android

View File

@ -1,63 +0,0 @@
/*
* Copyright (C) 2008 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_GPU_HARDWARE_H
#define ANDROID_GPU_HARDWARE_H
#include <stdint.h>
#include <sys/types.h>
#include <utils/RefBase.h>
#include <utils/threads.h>
#include <utils/KeyedVector.h>
#include <ui/ISurfaceComposer.h>
namespace android {
// ---------------------------------------------------------------------------
class IGPUCallback;
class GPUHardwareInterface : public virtual RefBase
{
public:
virtual void revoke(int pid) = 0;
virtual sp<MemoryDealer> request(int pid) = 0;
virtual status_t request(int pid, const sp<IGPUCallback>& callback,
ISurfaceComposer::gpu_info_t* gpu) = 0;
virtual status_t friendlyRevoke() = 0;
// used for debugging only...
virtual sp<SimpleBestFitAllocator> getAllocator() const = 0;
virtual pid_t getOwner() const = 0;
virtual void unconditionalRevoke() = 0;
};
// ---------------------------------------------------------------------------
class GPUFactory
{
public:
// the gpu factory
static sp<GPUHardwareInterface> getGPU();
};
// ---------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_GPU_HARDWARE_H

View File

@ -1,272 +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.
*/
#define LOG_TAG "SurfaceFlinger"
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <utils/StopWatch.h>
#include "BlurFilter.h"
#include "LayerBase.h"
#include "LayerOrientationAnim.h"
#include "SurfaceFlinger.h"
#include "DisplayHardware/DisplayHardware.h"
#include "OrientationAnimation.h"
namespace android {
// ---------------------------------------------------------------------------
const uint32_t LayerOrientationAnim::typeInfo = LayerBase::typeInfo | 0x80;
const char* const LayerOrientationAnim::typeID = "LayerOrientationAnim";
// ---------------------------------------------------------------------------
// Animation...
const float DURATION = ms2ns(200);
const float BOUNCES_PER_SECOND = 0.5f;
//const float BOUNCES_AMPLITUDE = 1.0f/16.0f;
const float BOUNCES_AMPLITUDE = 0;
const float DIM_TARGET = 0.40f;
//#define INTERPOLATED_TIME(_t) ((_t)*(_t))
#define INTERPOLATED_TIME(_t) (_t)
// ---------------------------------------------------------------------------
LayerOrientationAnim::LayerOrientationAnim(
SurfaceFlinger* flinger, DisplayID display,
OrientationAnimation* anim,
const sp<Buffer>& bitmapIn,
const sp<Buffer>& bitmapOut)
: LayerOrientationAnimBase(flinger, display), mAnim(anim),
mBitmapIn(bitmapIn), mBitmapOut(bitmapOut),
mTextureName(-1), mTextureNameIn(-1)
{
// blur that texture.
mStartTime = systemTime();
mFinishTime = 0;
mOrientationCompleted = false;
mFirstRedraw = false;
mLastNormalizedTime = 0;
mNeedsBlending = false;
mAlphaInLerp.set(1.0f, DIM_TARGET);
mAlphaOutLerp.set(0.5f, 1.0f);
}
LayerOrientationAnim::~LayerOrientationAnim()
{
if (mTextureName != -1U) {
glDeleteTextures(1, &mTextureName);
}
if (mTextureNameIn != -1U) {
glDeleteTextures(1, &mTextureNameIn);
}
}
bool LayerOrientationAnim::needsBlending() const
{
return mNeedsBlending;
}
Point LayerOrientationAnim::getPhysicalSize() const
{
const GraphicPlane& plane(graphicPlane(0));
const DisplayHardware& hw(plane.displayHardware());
return Point(hw.getWidth(), hw.getHeight());
}
void LayerOrientationAnim::validateVisibility(const Transform&)
{
const Layer::State& s(drawingState());
const Transform tr(s.transform);
const Point size(getPhysicalSize());
uint32_t w = size.x;
uint32_t h = size.y;
mTransformedBounds = tr.makeBounds(w, h);
mLeft = tr.tx();
mTop = tr.ty();
transparentRegionScreen.clear();
mTransformed = true;
}
void LayerOrientationAnim::onOrientationCompleted()
{
mFinishTime = systemTime();
mOrientationCompleted = true;
mFirstRedraw = true;
mNeedsBlending = true;
mFlinger->invalidateLayerVisibility(this);
}
void LayerOrientationAnim::onDraw(const Region& clip) const
{
const nsecs_t now = systemTime();
float alphaIn, alphaOut;
if (mOrientationCompleted) {
if (mFirstRedraw) {
mFirstRedraw = false;
// make a copy of what's on screen
copybit_image_t image;
mBitmapOut->getBitmapSurface(&image);
const DisplayHardware& hw(graphicPlane(0).displayHardware());
hw.copyBackToImage(image);
// and erase the screen for this round
glDisable(GL_BLEND);
glDisable(GL_DITHER);
glDisable(GL_SCISSOR_TEST);
glClearColor(0,0,0,0);
glClear(GL_COLOR_BUFFER_BIT);
// FIXME: code below is gross
mNeedsBlending = false;
LayerOrientationAnim* self(const_cast<LayerOrientationAnim*>(this));
mFlinger->invalidateLayerVisibility(self);
}
// make sure pick-up where we left off
const float duration = DURATION * mLastNormalizedTime;
const float normalizedTime = (float(now - mFinishTime) / duration);
if (normalizedTime <= 1.0f) {
const float interpolatedTime = INTERPOLATED_TIME(normalizedTime);
alphaIn = mAlphaInLerp.getOut();
alphaOut = mAlphaOutLerp(interpolatedTime);
} else {
mAnim->onAnimationFinished();
alphaIn = mAlphaInLerp.getOut();
alphaOut = mAlphaOutLerp.getOut();
}
} else {
const float normalizedTime = float(now - mStartTime) / DURATION;
if (normalizedTime <= 1.0f) {
mLastNormalizedTime = normalizedTime;
const float interpolatedTime = INTERPOLATED_TIME(normalizedTime);
alphaIn = mAlphaInLerp(interpolatedTime);
alphaOut = 0.0f;
} else {
mLastNormalizedTime = 1.0f;
const float to_seconds = DURATION / seconds(1);
alphaIn = mAlphaInLerp.getOut();
if (BOUNCES_AMPLITUDE > 0.0f) {
const float phi = BOUNCES_PER_SECOND *
(((normalizedTime - 1.0f) * to_seconds)*M_PI*2);
if (alphaIn > 1.0f) alphaIn = 1.0f;
else if (alphaIn < 0.0f) alphaIn = 0.0f;
alphaIn += BOUNCES_AMPLITUDE * (1.0f - cosf(phi));
}
alphaOut = 0.0f;
}
mAlphaOutLerp.setIn(alphaIn);
}
drawScaled(1.0f, alphaIn, alphaOut);
}
void LayerOrientationAnim::drawScaled(float scale, float alphaIn, float alphaOut) const
{
copybit_image_t dst;
const GraphicPlane& plane(graphicPlane(0));
const DisplayHardware& hw(plane.displayHardware());
//hw.getDisplaySurface(&dst);
// clear screen
// TODO: with update on demand, we may be able
// to not erase the screen at all during the animation
if (!mOrientationCompleted) {
if (scale==1.0f && (alphaIn>=1.0f || alphaOut>=1.0f)) {
// we don't need to erase the screen in that case
} else {
glDisable(GL_BLEND);
glDisable(GL_DITHER);
glDisable(GL_SCISSOR_TEST);
glClearColor(0,0,0,0);
glClear(GL_COLOR_BUFFER_BIT);
}
}
copybit_image_t src;
mBitmapIn->getBitmapSurface(&src);
copybit_image_t srcOut;
mBitmapOut->getBitmapSurface(&srcOut);
const int w = dst.w*scale;
const int h = dst.h*scale;
const int xc = uint32_t(dst.w-w)/2;
const int yc = uint32_t(dst.h-h)/2;
const copybit_rect_t drect = { xc, yc, xc+w, yc+h };
const copybit_rect_t srect = { 0, 0, src.w, src.h };
const Region reg(Rect( drect.l, drect.t, drect.r, drect.b ));
GGLSurface t;
t.version = sizeof(GGLSurface);
t.width = src.w;
t.height = src.h;
t.stride = src.w;
t.vstride= src.h;
t.format = src.format;
t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
Transform tr;
tr.set(scale,0,0,scale);
tr.set(xc, yc);
// FIXME: we should not access mVertices and mDrawingState like that,
// but since we control the animation, we know it's going to work okay.
// eventually we'd need a more formal way of doing things like this.
LayerOrientationAnim& self(const_cast<LayerOrientationAnim&>(*this));
tr.transform(self.mVertices[0], 0, 0);
tr.transform(self.mVertices[1], 0, src.h);
tr.transform(self.mVertices[2], src.w, src.h);
tr.transform(self.mVertices[3], src.w, 0);
if (!(mFlags & DisplayHardware::SLOW_CONFIG)) {
// Too slow to do this in software
self.mDrawingState.flags |= ISurfaceComposer::eLayerFilter;
}
if (alphaIn > 0.0f) {
t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
if (UNLIKELY(mTextureNameIn == -1LU)) {
mTextureNameIn = createTexture();
GLuint w=0, h=0;
const Region dirty(Rect(t.width, t.height));
loadTexture(dirty, mTextureNameIn, t, w, h);
}
self.mDrawingState.alpha = int(alphaIn*255);
drawWithOpenGL(reg, mTextureNameIn, t);
}
if (alphaOut > 0.0f) {
t.data = (GGLubyte*)(intptr_t(srcOut.base) + srcOut.offset);
if (UNLIKELY(mTextureName == -1LU)) {
mTextureName = createTexture();
GLuint w=0, h=0;
const Region dirty(Rect(t.width, t.height));
loadTexture(dirty, mTextureName, t, w, h);
}
self.mDrawingState.alpha = int(alphaOut*255);
drawWithOpenGL(reg, mTextureName, t);
}
}
// ---------------------------------------------------------------------------
}; // namespace android

View File

@ -1,112 +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_LAYER_ORIENTATION_ANIM_H
#define ANDROID_LAYER_ORIENTATION_ANIM_H
#include <stdint.h>
#include <sys/types.h>
#include <utils/threads.h>
#include <binder/Parcel.h>
#include "LayerBase.h"
#include "LayerBitmap.h"
namespace android {
// ---------------------------------------------------------------------------
class OrientationAnimation;
class LayerOrientationAnimBase : public LayerBase
{
public:
LayerOrientationAnimBase(SurfaceFlinger* flinger, DisplayID display)
: LayerBase(flinger, display) {
}
virtual void onOrientationCompleted() = 0;
};
// ---------------------------------------------------------------------------
class LayerOrientationAnim : public LayerOrientationAnimBase
{
public:
static const uint32_t typeInfo;
static const char* const typeID;
virtual char const* getTypeID() const { return typeID; }
virtual uint32_t getTypeInfo() const { return typeInfo; }
LayerOrientationAnim(SurfaceFlinger* flinger, DisplayID display,
OrientationAnimation* anim,
const sp<Buffer>& bitmapIn,
const sp<Buffer>& bitmapOut);
virtual ~LayerOrientationAnim();
void onOrientationCompleted();
virtual void onDraw(const Region& clip) const;
virtual Point getPhysicalSize() const;
virtual void validateVisibility(const Transform& globalTransform);
virtual bool needsBlending() const;
virtual bool isSecure() const { return false; }
private:
void drawScaled(float scale, float alphaIn, float alphaOut) const;
class Lerp {
float in;
float outMinusIn;
public:
Lerp() : in(0), outMinusIn(0) { }
Lerp(float in, float out) : in(in), outMinusIn(out-in) { }
float getIn() const { return in; };
float getOut() const { return in + outMinusIn; }
void set(float in, float out) {
this->in = in;
this->outMinusIn = out-in;
}
void setIn(float in) {
this->in = in;
}
void setOut(float out) {
this->outMinusIn = out - this->in;
}
float operator()(float t) const {
return outMinusIn*t + in;
}
};
OrientationAnimation* mAnim;
sp<Buffer> mBitmapIn;
sp<Buffer> mBitmapOut;
nsecs_t mStartTime;
nsecs_t mFinishTime;
bool mOrientationCompleted;
mutable bool mFirstRedraw;
mutable float mLastNormalizedTime;
mutable GLuint mTextureName;
mutable GLuint mTextureNameIn;
mutable bool mNeedsBlending;
mutable Lerp mAlphaInLerp;
mutable Lerp mAlphaOutLerp;
};
// ---------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_LAYER_ORIENTATION_ANIM_H

View File

@ -1,269 +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.
*/
#define LOG_TAG "SurfaceFlinger"
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include "LayerBase.h"
#include "LayerOrientationAnim.h"
#include "LayerOrientationAnimRotate.h"
#include "SurfaceFlinger.h"
#include "DisplayHardware/DisplayHardware.h"
#include "OrientationAnimation.h"
namespace android {
// ---------------------------------------------------------------------------
const uint32_t LayerOrientationAnimRotate::typeInfo = LayerBase::typeInfo | 0x100;
const char* const LayerOrientationAnimRotate::typeID = "LayerOrientationAnimRotate";
// ---------------------------------------------------------------------------
const float ROTATION = M_PI * 0.5f;
const float ROTATION_FACTOR = 1.0f; // 1.0 or 2.0
const float DURATION = ms2ns(200);
const float BOUNCES_PER_SECOND = 0.8;
const float BOUNCES_AMPLITUDE = (5.0f/180.f) * M_PI;
LayerOrientationAnimRotate::LayerOrientationAnimRotate(
SurfaceFlinger* flinger, DisplayID display,
OrientationAnimation* anim,
const sp<Buffer>& bitmapIn,
const sp<Buffer>& bitmapOut)
: LayerOrientationAnimBase(flinger, display), mAnim(anim),
mBitmapIn(bitmapIn), mBitmapOut(bitmapOut),
mTextureName(-1), mTextureNameIn(-1)
{
mStartTime = systemTime();
mFinishTime = 0;
mOrientationCompleted = false;
mFirstRedraw = false;
mLastNormalizedTime = 0;
mLastAngle = 0;
mLastScale = 0;
mNeedsBlending = false;
const GraphicPlane& plane(graphicPlane(0));
mOriginalTargetOrientation = plane.getOrientation();
}
LayerOrientationAnimRotate::~LayerOrientationAnimRotate()
{
if (mTextureName != -1U) {
glDeleteTextures(1, &mTextureName);
}
if (mTextureNameIn != -1U) {
glDeleteTextures(1, &mTextureNameIn);
}
}
bool LayerOrientationAnimRotate::needsBlending() const
{
return mNeedsBlending;
}
Point LayerOrientationAnimRotate::getPhysicalSize() const
{
const GraphicPlane& plane(graphicPlane(0));
const DisplayHardware& hw(plane.displayHardware());
return Point(hw.getWidth(), hw.getHeight());
}
void LayerOrientationAnimRotate::validateVisibility(const Transform&)
{
const Layer::State& s(drawingState());
const Transform tr(s.transform);
const Point size(getPhysicalSize());
uint32_t w = size.x;
uint32_t h = size.y;
mTransformedBounds = tr.makeBounds(w, h);
mLeft = tr.tx();
mTop = tr.ty();
transparentRegionScreen.clear();
mTransformed = true;
}
void LayerOrientationAnimRotate::onOrientationCompleted()
{
mFinishTime = systemTime();
mOrientationCompleted = true;
mFirstRedraw = true;
mNeedsBlending = true;
mFlinger->invalidateLayerVisibility(this);
}
void LayerOrientationAnimRotate::onDraw(const Region& clip) const
{
// Animation...
const nsecs_t now = systemTime();
float angle, scale, alpha;
if (mOrientationCompleted) {
if (mFirstRedraw) {
// make a copy of what's on screen
copybit_image_t image;
mBitmapIn->getBitmapSurface(&image);
const DisplayHardware& hw(graphicPlane(0).displayHardware());
hw.copyBackToImage(image);
// FIXME: code below is gross
mFirstRedraw = false;
mNeedsBlending = false;
LayerOrientationAnimRotate* self(const_cast<LayerOrientationAnimRotate*>(this));
mFlinger->invalidateLayerVisibility(self);
}
// make sure pick-up where we left off
const float duration = DURATION * mLastNormalizedTime;
const float normalizedTime = (float(now - mFinishTime) / duration);
if (normalizedTime <= 1.0f) {
const float squaredTime = normalizedTime*normalizedTime;
angle = (ROTATION*ROTATION_FACTOR - mLastAngle)*squaredTime + mLastAngle;
scale = (1.0f - mLastScale)*squaredTime + mLastScale;
alpha = normalizedTime;
} else {
mAnim->onAnimationFinished();
angle = ROTATION;
alpha = 1.0f;
scale = 1.0f;
}
} else {
// FIXME: works only for portrait framebuffers
const Point size(getPhysicalSize());
const float TARGET_SCALE = size.x * (1.0f / size.y);
const float normalizedTime = float(now - mStartTime) / DURATION;
if (normalizedTime <= 1.0f) {
mLastNormalizedTime = normalizedTime;
const float squaredTime = normalizedTime*normalizedTime;
angle = ROTATION * squaredTime;
scale = (TARGET_SCALE - 1.0f)*squaredTime + 1.0f;
alpha = 0;
} else {
mLastNormalizedTime = 1.0f;
angle = ROTATION;
if (BOUNCES_AMPLITUDE) {
const float to_seconds = DURATION / seconds(1);
const float phi = BOUNCES_PER_SECOND *
(((normalizedTime - 1.0f) * to_seconds)*M_PI*2);
angle += BOUNCES_AMPLITUDE * sinf(phi);
}
scale = TARGET_SCALE;
alpha = 0;
}
mLastAngle = angle;
mLastScale = scale;
}
drawScaled(angle, scale, alpha);
}
void LayerOrientationAnimRotate::drawScaled(float f, float s, float alpha) const
{
copybit_image_t dst;
const GraphicPlane& plane(graphicPlane(0));
const DisplayHardware& hw(plane.displayHardware());
//hw.getDisplaySurface(&dst);
// clear screen
// TODO: with update on demand, we may be able
// to not erase the screen at all during the animation
glDisable(GL_BLEND);
glDisable(GL_DITHER);
glDisable(GL_SCISSOR_TEST);
glClearColor(0,0,0,0);
glClear(GL_COLOR_BUFFER_BIT);
const int w = dst.w;
const int h = dst.h;
copybit_image_t src;
mBitmapIn->getBitmapSurface(&src);
const copybit_rect_t srect = { 0, 0, src.w, src.h };
GGLSurface t;
t.version = sizeof(GGLSurface);
t.width = src.w;
t.height = src.h;
t.stride = src.w;
t.vstride= src.h;
t.format = src.format;
t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
if (!mOriginalTargetOrientation) {
f = -f;
}
Transform tr;
tr.set(f, w*0.5f, h*0.5f);
tr.scale(s, w*0.5f, h*0.5f);
// FIXME: we should not access mVertices and mDrawingState like that,
// but since we control the animation, we know it's going to work okay.
// eventually we'd need a more formal way of doing things like this.
LayerOrientationAnimRotate& self(const_cast<LayerOrientationAnimRotate&>(*this));
tr.transform(self.mVertices[0], 0, 0);
tr.transform(self.mVertices[1], 0, src.h);
tr.transform(self.mVertices[2], src.w, src.h);
tr.transform(self.mVertices[3], src.w, 0);
if (!(mFlags & DisplayHardware::SLOW_CONFIG)) {
// Too slow to do this in software
self.mDrawingState.flags |= ISurfaceComposer::eLayerFilter;
}
if (UNLIKELY(mTextureName == -1LU)) {
mTextureName = createTexture();
GLuint w=0, h=0;
const Region dirty(Rect(t.width, t.height));
loadTexture(dirty, mTextureName, t, w, h);
}
self.mDrawingState.alpha = 255; //-int(alpha*255);
const Region clip(Rect( srect.l, srect.t, srect.r, srect.b ));
drawWithOpenGL(clip, mTextureName, t);
if (alpha > 0) {
const float sign = (!mOriginalTargetOrientation) ? 1.0f : -1.0f;
tr.set(f + sign*(M_PI * 0.5f * ROTATION_FACTOR), w*0.5f, h*0.5f);
tr.scale(s, w*0.5f, h*0.5f);
tr.transform(self.mVertices[0], 0, 0);
tr.transform(self.mVertices[1], 0, src.h);
tr.transform(self.mVertices[2], src.w, src.h);
tr.transform(self.mVertices[3], src.w, 0);
copybit_image_t src;
mBitmapIn->getBitmapSurface(&src);
t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
if (UNLIKELY(mTextureNameIn == -1LU)) {
mTextureNameIn = createTexture();
GLuint w=0, h=0;
const Region dirty(Rect(t.width, t.height));
loadTexture(dirty, mTextureNameIn, t, w, h);
}
self.mDrawingState.alpha = int(alpha*255);
const Region clip(Rect( srect.l, srect.t, srect.r, srect.b ));
drawWithOpenGL(clip, mTextureNameIn, t);
}
}
// ---------------------------------------------------------------------------
}; // namespace android

View File

@ -1,77 +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_LAYER_ORIENTATION_ANIM_ROTATE_H
#define ANDROID_LAYER_ORIENTATION_ANIM_ROTATE_H
#include <stdint.h>
#include <sys/types.h>
#include <utils/threads.h>
#include <binder/Parcel.h>
#include "LayerBase.h"
#include "LayerBitmap.h"
namespace android {
// ---------------------------------------------------------------------------
class OrientationAnimation;
class LayerOrientationAnimRotate : public LayerOrientationAnimBase
{
public:
static const uint32_t typeInfo;
static const char* const typeID;
virtual char const* getTypeID() const { return typeID; }
virtual uint32_t getTypeInfo() const { return typeInfo; }
LayerOrientationAnimRotate(SurfaceFlinger* flinger, DisplayID display,
OrientationAnimation* anim,
const sp<Buffer>& bitmapIn,
const sp<Buffer>& bitmapOut);
virtual ~LayerOrientationAnimRotate();
void onOrientationCompleted();
virtual void onDraw(const Region& clip) const;
virtual Point getPhysicalSize() const;
virtual void validateVisibility(const Transform& globalTransform);
virtual bool needsBlending() const;
virtual bool isSecure() const { return false; }
private:
void drawScaled(float angle, float scale, float alpha) const;
OrientationAnimation* mAnim;
sp<Buffer> mBitmapIn;
sp<Buffer> mBitmapOut;
nsecs_t mStartTime;
nsecs_t mFinishTime;
bool mOrientationCompleted;
int mOriginalTargetOrientation;
mutable bool mFirstRedraw;
mutable float mLastNormalizedTime;
mutable float mLastAngle;
mutable float mLastScale;
mutable GLuint mTextureName;
mutable GLuint mTextureNameIn;
mutable bool mNeedsBlending;
};
// ---------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_LAYER_ORIENTATION_ANIM_ROTATE_H

View File

@ -1,150 +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 <stdint.h>
#include <sys/types.h>
#include <limits.h>
#include "LayerOrientationAnim.h"
#include "LayerOrientationAnimRotate.h"
#include "OrientationAnimation.h"
#include "SurfaceFlinger.h"
#include "DisplayHardware/DisplayHardware.h"
namespace android {
// ---------------------------------------------------------------------------
OrientationAnimation::OrientationAnimation(const sp<SurfaceFlinger>& flinger)
: mFlinger(flinger), mLayerOrientationAnim(NULL), mState(DONE)
{
}
OrientationAnimation::~OrientationAnimation()
{
}
void OrientationAnimation::onOrientationChanged(uint32_t type)
{
if (mState == DONE) {
mType = type;
if (!(type & ISurfaceComposer::eOrientationAnimationDisable)) {
mState = PREPARE;
}
}
}
void OrientationAnimation::onAnimationFinished()
{
if (mState != DONE)
mState = FINISH;
}
bool OrientationAnimation::run_impl()
{
bool skip_frame;
switch (mState) {
default:
case DONE:
skip_frame = done();
break;
case PREPARE:
skip_frame = prepare();
break;
case PHASE1:
skip_frame = phase1();
break;
case PHASE2:
skip_frame = phase2();
break;
case FINISH:
skip_frame = finished();
break;
}
return skip_frame;
}
bool OrientationAnimation::done()
{
return done_impl();
}
bool OrientationAnimation::prepare()
{
mState = PHASE1;
const GraphicPlane& plane(mFlinger->graphicPlane(0));
const DisplayHardware& hw(plane.displayHardware());
const uint32_t w = hw.getWidth();
const uint32_t h = hw.getHeight();
sp<Buffer> bitmap = new Buffer(w, h, hw.getFormat());
sp<Buffer> bitmapIn = new Buffer(w, h, hw.getFormat());
copybit_image_t front;
bitmap->getBitmapSurface(&front);
hw.copyFrontToImage(front); // FIXME: we need an extension to do this
sp<LayerOrientationAnimBase> l;
if (mType & 0x80) {
l = new LayerOrientationAnimRotate(
mFlinger.get(), 0, this, bitmap, bitmapIn);
} else {
l = new LayerOrientationAnim(
mFlinger.get(), 0, this, bitmap, bitmapIn);
}
l->initStates(w, h, 0);
l->setLayer(INT_MAX-1);
mFlinger->addLayer(l);
mLayerOrientationAnim = l;
return true;
}
bool OrientationAnimation::phase1()
{
if (mFlinger->isFrozen() == false) {
// start phase 2
mState = PHASE2;
mLayerOrientationAnim->onOrientationCompleted();
mLayerOrientationAnim->invalidate();
return true;
}
mLayerOrientationAnim->invalidate();
return false;
}
bool OrientationAnimation::phase2()
{
// do the 2nd phase of the animation
mLayerOrientationAnim->invalidate();
return false;
}
bool OrientationAnimation::finished()
{
mState = DONE;
mFlinger->removeLayer(mLayerOrientationAnim);
mLayerOrientationAnim.clear();
return true;
}
// ---------------------------------------------------------------------------
}; // namespace android

View File

@ -1,84 +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_ORIENTATION_ANIMATION_H
#define ANDROID_ORIENTATION_ANIMATION_H
#include <stdint.h>
#include <sys/types.h>
#include "SurfaceFlinger.h"
namespace android {
// ---------------------------------------------------------------------------
class SurfaceFlinger;
class MemoryDealer;
class LayerOrientationAnim;
class OrientationAnimation
{
public:
OrientationAnimation(const sp<SurfaceFlinger>& flinger);
virtual ~OrientationAnimation();
void onOrientationChanged(uint32_t type);
void onAnimationFinished();
inline bool run() {
if (LIKELY(mState == DONE))
return done_impl();
return run_impl();
}
private:
enum {
DONE = 0,
PREPARE,
PHASE1,
PHASE2,
FINISH
};
bool run_impl();
inline bool done_impl() {
if (mFlinger->isFrozen()) {
// we are not allowed to draw, but pause a bit to make sure
// apps don't end up using the whole CPU, if they depend on
// surfaceflinger for synchronization.
usleep(8333); // 8.3ms ~ 120fps
return true;
}
return false;
}
bool done();
bool prepare();
bool phase1();
bool phase2();
bool finished();
sp<SurfaceFlinger> mFlinger;
sp< LayerOrientationAnimBase > mLayerOrientationAnim;
int mState;
uint32_t mType;
};
// ---------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_ORIENTATION_ANIMATION_H

View File

@ -1,174 +0,0 @@
/*
* Copyright (C) 2008 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 <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <cutils/log.h>
#include <cutils/properties.h>
#include <utils/MemoryDealer.h>
#include <utils/MemoryBase.h>
#include <utils/MemoryHeapPmem.h>
#include <utils/MemoryHeapBase.h>
#include "GPUHardware/GPUHardware.h"
#include "SurfaceFlinger.h"
#include "VRamHeap.h"
#if HAVE_ANDROID_OS
#include <linux/android_pmem.h>
#endif
namespace android {
// ---------------------------------------------------------------------------
/*
* Amount of memory we reserve for surface, per client in PMEM
* (PMEM is used for 2D acceleration)
* 8 MB of address space per client should be enough.
*/
static const int PMEM_SIZE = int(8 * 1024 * 1024);
int SurfaceHeapManager::global_pmem_heap = 0;
// ---------------------------------------------------------------------------
SurfaceHeapManager::SurfaceHeapManager(const sp<SurfaceFlinger>& flinger,
size_t clientHeapSize)
: mFlinger(flinger), mClientHeapSize(clientHeapSize)
{
SurfaceHeapManager::global_pmem_heap = 1;
}
SurfaceHeapManager::~SurfaceHeapManager()
{
}
void SurfaceHeapManager::onFirstRef()
{
if (global_pmem_heap) {
const char* device = "/dev/pmem";
mPMemHeap = new PMemHeap(device, PMEM_SIZE);
if (mPMemHeap->base() == MAP_FAILED) {
mPMemHeap.clear();
global_pmem_heap = 0;
}
}
}
sp<MemoryDealer> SurfaceHeapManager::createHeap(
uint32_t flags,
pid_t client_pid,
const sp<MemoryDealer>& defaultAllocator)
{
sp<MemoryDealer> dealer;
if (flags & ISurfaceComposer::eGPU) {
// don't grant GPU memory if GPU is disabled
char value[PROPERTY_VALUE_MAX];
property_get("debug.egl.hw", value, "1");
if (atoi(value) == 0) {
flags &= ~ISurfaceComposer::eGPU;
}
}
if (flags & ISurfaceComposer::eGPU) {
// FIXME: this is msm7201A specific, where gpu surfaces may not be secure
if (!(flags & ISurfaceComposer::eSecure)) {
// if GPU doesn't work, we try eHardware
flags |= ISurfaceComposer::eHardware;
// asked for GPU memory, try that first
dealer = mFlinger->getGPU()->request(client_pid);
}
}
if (dealer == NULL) {
if (defaultAllocator != NULL)
// if a default allocator is given, use that
dealer = defaultAllocator;
}
if (dealer == NULL) {
// always try h/w accelerated memory first
if (global_pmem_heap) {
const sp<PMemHeap>& heap(mPMemHeap);
if (dealer == NULL && heap != NULL) {
dealer = new MemoryDealer(
heap->createClientHeap(),
heap->getAllocator());
}
}
}
if (dealer == NULL) {
// return the ashmem allocator (software rendering)
dealer = new MemoryDealer(mClientHeapSize, 0, "SFNativeHeap");
}
return dealer;
}
sp<SimpleBestFitAllocator> SurfaceHeapManager::getAllocator(int type) const
{
Mutex::Autolock _l(mLock);
sp<SimpleBestFitAllocator> allocator;
// this is only used for debugging
switch (type) {
case NATIVE_MEMORY_TYPE_PMEM:
if (mPMemHeap != 0) {
allocator = mPMemHeap->getAllocator();
}
break;
}
return allocator;
}
// ---------------------------------------------------------------------------
PMemHeap::PMemHeap(const char* const device, size_t size, size_t reserved)
: MemoryHeapBase(device, size)
{
//LOGD("%s, %p, mFD=%d", __PRETTY_FUNCTION__, this, heapID());
if (base() != MAP_FAILED) {
//LOGD("%s, %u bytes", device, virtualSize());
if (reserved == 0)
reserved = virtualSize();
mAllocator = new SimpleBestFitAllocator(reserved);
}
}
PMemHeap::~PMemHeap() {
//LOGD("%s, %p, mFD=%d", __PRETTY_FUNCTION__, this, heapID());
}
sp<MemoryHeapPmem> PMemHeap::createClientHeap() {
sp<MemoryHeapBase> parentHeap(this);
return new MemoryHeapPmem(parentHeap);
}
// ---------------------------------------------------------------------------
}; // namespace android

View File

@ -1,78 +0,0 @@
/*
* Copyright (C) 2008 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_VRAM_HEAP_H
#define ANDROID_VRAM_HEAP_H
#include <stdint.h>
#include <sys/types.h>
#include <utils/MemoryDealer.h>
namespace android {
// ---------------------------------------------------------------------------
class PMemHeap;
class MemoryHeapPmem;
class SurfaceFlinger;
// ---------------------------------------------------------------------------
class SurfaceHeapManager : public RefBase
{
public:
SurfaceHeapManager(const sp<SurfaceFlinger>& flinger, size_t clientHeapSize);
virtual ~SurfaceHeapManager();
virtual void onFirstRef();
/* use ISurfaceComposer flags eGPU|eHArdware|eSecure */
sp<MemoryDealer> createHeap(uint32_t flags=0, pid_t client_pid = 0,
const sp<MemoryDealer>& defaultAllocator = 0);
// used for debugging only...
sp<SimpleBestFitAllocator> getAllocator(int type) const;
private:
sp<PMemHeap> getHeap(int type) const;
sp<SurfaceFlinger> mFlinger;
mutable Mutex mLock;
size_t mClientHeapSize;
sp<PMemHeap> mPMemHeap;
static int global_pmem_heap;
};
// ---------------------------------------------------------------------------
class PMemHeap : public MemoryHeapBase
{
public:
PMemHeap(const char* const vram,
size_t size=0, size_t reserved=0);
virtual ~PMemHeap();
virtual const sp<SimpleBestFitAllocator>& getAllocator() const {
return mAllocator;
}
virtual sp<MemoryHeapPmem> createClientHeap();
private:
sp<SimpleBestFitAllocator> mAllocator;
};
// ---------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_VRAM_HEAP_H

View File

@ -23,7 +23,9 @@ LOCAL_SRC_FILES:= \
PixelFormat.cpp \
Rect.cpp \
Region.cpp \
SharedBufferStack.cpp \
Surface.cpp \
SurfaceBuffer.cpp \
SurfaceComposerClient.cpp \
SurfaceFlingerSynchro.cpp

View File

@ -71,12 +71,13 @@ public:
{
}
virtual sp<SurfaceBuffer> getBuffer(int usage)
virtual sp<SurfaceBuffer> requestBuffer(int bufferIdx, int usage)
{
Parcel data, reply;
data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
data.writeInt32(bufferIdx);
data.writeInt32(usage);
remote()->transact(GET_BUFFER, data, &reply);
remote()->transact(REQUEST_BUFFER, data, &reply);
sp<SurfaceBuffer> buffer = new SurfaceBuffer(reply);
return buffer;
}
@ -134,10 +135,11 @@ status_t BnSurface::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
case GET_BUFFER: {
case REQUEST_BUFFER: {
CHECK_INTERFACE(ISurface, data, reply);
int bufferIdx = data.readInt32();
int usage = data.readInt32();
sp<SurfaceBuffer> buffer(getBuffer(usage));
sp<SurfaceBuffer> buffer(requestBuffer(bufferIdx, usage));
return SurfaceBuffer::writeToParcel(reply, buffer.get());
}
case REGISTER_BUFFERS: {

View File

@ -0,0 +1,352 @@
/*
* 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.
*/
#define LOG_TAG "SharedBufferStack"
#include <stdint.h>
#include <sys/types.h>
#include <utils/Debug.h>
#include <utils/Log.h>
#include <utils/threads.h>
#include <private/ui/SharedBufferStack.h>
#include <ui/Rect.h>
#include <ui/Region.h>
#define DEBUG_ATOMICS 0
namespace android {
// ----------------------------------------------------------------------------
SharedClient::SharedClient()
: lock(Mutex::SHARED)
{
}
SharedClient::~SharedClient() {
}
// these functions are used by the clients
status_t SharedClient::validate(size_t i) const {
if (uint32_t(i) >= uint32_t(NUM_LAYERS_MAX))
return BAD_INDEX;
return surfaces[i].status;
}
uint32_t SharedClient::getIdentity(size_t token) const {
return uint32_t(surfaces[token].identity);
}
status_t SharedClient::setIdentity(size_t token, uint32_t identity) {
if (token >= NUM_LAYERS_MAX)
return BAD_INDEX;
surfaces[token].identity = identity;
return NO_ERROR;
}
// ----------------------------------------------------------------------------
SharedBufferStack::SharedBufferStack()
: inUse(-1), identity(-1), status(NO_ERROR)
{
}
status_t SharedBufferStack::setDirtyRegion(int buffer, const Region& dirty)
{
if (uint32_t(buffer) >= NUM_BUFFER_MAX)
return BAD_INDEX;
// in the current implementation we only send a single rectangle
const Rect bounds(dirty.getBounds());
FlatRegion& reg(dirtyRegion[buffer]);
reg.count = 1;
reg.rects[0] = uint16_t(bounds.left);
reg.rects[1] = uint16_t(bounds.top);
reg.rects[2] = uint16_t(bounds.right);
reg.rects[3] = uint16_t(bounds.bottom);
return NO_ERROR;
}
Region SharedBufferStack::getDirtyRegion(int buffer) const
{
Region res;
if (uint32_t(buffer) >= NUM_BUFFER_MAX)
return res;
const FlatRegion& reg(dirtyRegion[buffer]);
res.set(Rect(reg.rects[0], reg.rects[1], reg.rects[2], reg.rects[3]));
return res;
}
// ----------------------------------------------------------------------------
SharedBufferBase::SharedBufferBase(SharedClient* sharedClient,
int surface, int num)
: mSharedClient(sharedClient),
mSharedStack(sharedClient->surfaces + surface),
mNumBuffers(num)
{
}
SharedBufferBase::~SharedBufferBase()
{
}
uint32_t SharedBufferBase::getIdentity()
{
SharedBufferStack& stack( *mSharedStack );
return stack.identity;
}
size_t SharedBufferBase::getFrontBuffer() const
{
SharedBufferStack& stack( *mSharedStack );
return size_t( stack.head );
}
String8 SharedBufferBase::dump(char const* prefix) const
{
const size_t SIZE = 1024;
char buffer[SIZE];
String8 result;
SharedBufferStack& stack( *mSharedStack );
snprintf(buffer, SIZE,
"%s[ head=%2d, available=%2d, queued=%2d ] "
"reallocMask=%08x, inUse=%2d, identity=%d, status=%d\n",
prefix, stack.head, stack.available, stack.queued,
stack.reallocMask, stack.inUse, stack.identity, stack.status);
result.append(buffer);
return result;
}
// ============================================================================
// conditions and updates
// ============================================================================
SharedBufferClient::DequeueCondition::DequeueCondition(
SharedBufferClient* sbc) : ConditionBase(sbc) {
}
bool SharedBufferClient::DequeueCondition::operator()() {
return stack.available > 0;
}
SharedBufferClient::LockCondition::LockCondition(
SharedBufferClient* sbc, int buf) : ConditionBase(sbc), buf(buf) {
}
bool SharedBufferClient::LockCondition::operator()() {
return (buf != stack.head ||
(stack.queued > 0 && stack.inUse != buf));
}
SharedBufferServer::ReallocateCondition::ReallocateCondition(
SharedBufferBase* sbb, int buf) : ConditionBase(sbb), buf(buf) {
}
bool SharedBufferServer::ReallocateCondition::operator()() {
// TODO: we should also check that buf has been dequeued
return (buf != stack.head);
}
// ----------------------------------------------------------------------------
SharedBufferClient::QueueUpdate::QueueUpdate(SharedBufferBase* sbb)
: UpdateBase(sbb) {
}
ssize_t SharedBufferClient::QueueUpdate::operator()() {
android_atomic_inc(&stack.queued);
return NO_ERROR;
}
SharedBufferClient::UndoDequeueUpdate::UndoDequeueUpdate(SharedBufferBase* sbb)
: UpdateBase(sbb) {
}
ssize_t SharedBufferClient::UndoDequeueUpdate::operator()() {
android_atomic_inc(&stack.available);
return NO_ERROR;
}
SharedBufferServer::UnlockUpdate::UnlockUpdate(
SharedBufferBase* sbb, int lockedBuffer)
: UpdateBase(sbb), lockedBuffer(lockedBuffer) {
}
ssize_t SharedBufferServer::UnlockUpdate::operator()() {
if (stack.inUse != lockedBuffer) {
LOGE("unlocking %d, but currently locked buffer is %d",
lockedBuffer, stack.inUse);
return BAD_VALUE;
}
android_atomic_write(-1, &stack.inUse);
return NO_ERROR;
}
SharedBufferServer::RetireUpdate::RetireUpdate(
SharedBufferBase* sbb, int numBuffers)
: UpdateBase(sbb), numBuffers(numBuffers) {
}
ssize_t SharedBufferServer::RetireUpdate::operator()() {
// head is only written in this function, which is single-thread.
int32_t head = stack.head;
// Preventively lock the current buffer before updating queued.
android_atomic_write(head, &stack.inUse);
// Decrement the number of queued buffers
int32_t queued;
do {
queued = stack.queued;
if (queued == 0) {
return NOT_ENOUGH_DATA;
}
} while (android_atomic_cmpxchg(queued, queued-1, &stack.queued));
// update the head pointer
head = ((head+1 >= numBuffers) ? 0 : head+1);
// lock the buffer before advancing head, which automatically unlocks
// the buffer we preventively locked upon entering this function
android_atomic_write(head, &stack.inUse);
// advance head
android_atomic_write(head, &stack.head);
// now that head has moved, we can increment the number of available buffers
android_atomic_inc(&stack.available);
return head;
}
// ============================================================================
SharedBufferClient::SharedBufferClient(SharedClient* sharedClient,
int surface, int num)
: SharedBufferBase(sharedClient, surface, num), tail(0)
{
}
ssize_t SharedBufferClient::dequeue()
{
//LOGD("[%d] about to dequeue a buffer",
// mSharedStack->identity);
DequeueCondition condition(this);
status_t err = waitForCondition(condition);
if (err != NO_ERROR)
return ssize_t(err);
SharedBufferStack& stack( *mSharedStack );
// NOTE: 'stack.available' is part of the conditions, however
// decrementing it, never changes any conditions, so we don't need
// to do this as part of an update.
if (android_atomic_dec(&stack.available) == 0) {
LOGW("dequeue probably called from multiple threads!");
}
int dequeued = tail;
tail = ((tail+1 >= mNumBuffers) ? 0 : tail+1);
LOGD_IF(DEBUG_ATOMICS, "dequeued=%d, tail=%d, %s",
dequeued, tail, dump("").string());
return dequeued;
}
status_t SharedBufferClient::undoDequeue(int buf)
{
UndoDequeueUpdate update(this);
status_t err = updateCondition( update );
return err;
}
status_t SharedBufferClient::lock(int buf)
{
LockCondition condition(this, buf);
status_t err = waitForCondition(condition);
return err;
}
status_t SharedBufferClient::queue(int buf)
{
QueueUpdate update(this);
status_t err = updateCondition( update );
LOGD_IF(DEBUG_ATOMICS, "queued=%d, %s", buf, dump("").string());
return err;
}
bool SharedBufferClient::needNewBuffer(int buffer) const
{
SharedBufferStack& stack( *mSharedStack );
const uint32_t mask = 1<<buffer;
return (android_atomic_and(~mask, &stack.reallocMask) & mask) != 0;
}
status_t SharedBufferClient::setDirtyRegion(int buffer, const Region& reg)
{
SharedBufferStack& stack( *mSharedStack );
return stack.setDirtyRegion(buffer, reg);
}
// ----------------------------------------------------------------------------
SharedBufferServer::SharedBufferServer(SharedClient* sharedClient,
int surface, int num)
: SharedBufferBase(sharedClient, surface, num)
{
mSharedStack->head = num-1;
mSharedStack->available = num;
mSharedStack->queued = 0;
mSharedStack->reallocMask = 0;
memset(mSharedStack->dirtyRegion, 0, sizeof(mSharedStack->dirtyRegion));
}
ssize_t SharedBufferServer::retireAndLock()
{
RetireUpdate update(this, mNumBuffers);
ssize_t buf = updateCondition( update );
LOGD_IF(DEBUG_ATOMICS, "retire=%d, %s", int(buf), dump("").string());
return buf;
}
status_t SharedBufferServer::unlock(int buffer)
{
UnlockUpdate update(this, buffer);
status_t err = updateCondition( update );
return err;
}
status_t SharedBufferServer::reallocate()
{
SharedBufferStack& stack( *mSharedStack );
uint32_t mask = (1<<mNumBuffers)-1;
android_atomic_or(mask, &stack.reallocMask);
return NO_ERROR;
}
status_t SharedBufferServer::assertReallocate(int buffer)
{
ReallocateCondition condition(this, buffer);
status_t err = waitForCondition(condition);
return err;
}
Region SharedBufferServer::getDirtyRegion(int buffer) const
{
SharedBufferStack& stack( *mSharedStack );
return stack.getDirtyRegion(buffer);
}
// ---------------------------------------------------------------------------
}; // namespace android

View File

@ -25,6 +25,7 @@
#include <utils/Errors.h>
#include <utils/threads.h>
#include <utils/CallStack.h>
#include <binder/IPCThreadState.h>
#include <binder/IMemory.h>
#include <utils/Log.h>
@ -38,102 +39,12 @@
#include <pixelflinger/pixelflinger.h>
#include <private/ui/SharedState.h>
#include <private/ui/SharedBufferStack.h>
#include <private/ui/LayerState.h>
#include <private/ui/SurfaceBuffer.h>
namespace android {
// ============================================================================
// SurfaceBuffer
// ============================================================================
SurfaceBuffer::SurfaceBuffer()
: BASE(), mOwner(false), mBufferMapper(BufferMapper::get())
{
width =
height =
stride =
format =
usage = 0;
handle = NULL;
}
SurfaceBuffer::SurfaceBuffer(const Parcel& data)
: BASE(), mOwner(true), mBufferMapper(BufferMapper::get())
{
// we own the handle in this case
width = data.readInt32();
if (width < 0) {
width = height = stride = format = usage = 0;
handle = 0;
} else {
height = data.readInt32();
stride = data.readInt32();
format = data.readInt32();
usage = data.readInt32();
handle = data.readNativeHandle();
}
}
SurfaceBuffer::~SurfaceBuffer()
{
if (handle && mOwner) {
native_handle_close(handle);
native_handle_delete(const_cast<native_handle*>(handle));
}
}
status_t SurfaceBuffer::lock(uint32_t usage, void** vaddr)
{
const Rect lockBounds(width, height);
status_t res = lock(usage, lockBounds, vaddr);
return res;
}
status_t SurfaceBuffer::lock(uint32_t usage, const Rect& rect, void** vaddr)
{
if (rect.left < 0 || rect.right > this->width ||
rect.top < 0 || rect.bottom > this->height) {
LOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)",
rect.left, rect.top, rect.right, rect.bottom,
this->width, this->height);
return BAD_VALUE;
}
status_t res = getBufferMapper().lock(handle, usage, rect, vaddr);
return res;
}
status_t SurfaceBuffer::unlock()
{
status_t res = getBufferMapper().unlock(handle);
return res;
}
status_t SurfaceBuffer::writeToParcel(Parcel* reply,
android_native_buffer_t const* buffer)
{
if (buffer == NULL)
return BAD_VALUE;
if (buffer->width < 0 || buffer->height < 0)
return BAD_VALUE;
status_t err = NO_ERROR;
if (buffer->handle == NULL) {
// this buffer doesn't have a handle
reply->writeInt32(NO_MEMORY);
} else {
reply->writeInt32(buffer->width);
reply->writeInt32(buffer->height);
reply->writeInt32(buffer->stride);
reply->writeInt32(buffer->format);
reply->writeInt32(buffer->usage);
err = reply->writeNativeHandle(buffer->handle);
}
return err;
}
// ----------------------------------------------------------------------
static status_t copyBlt(
@ -324,7 +235,7 @@ status_t SurfaceControl::setFreezeTint(uint32_t tint) {
return client->setFreezeTint(mToken, tint);
}
status_t SurfaceControl::validate(per_client_cblk_t const* cblk) const
status_t SurfaceControl::validate(SharedClient const* cblk) const
{
if (mToken<0 || mClient==0) {
LOGE("invalid token (%d, identity=%u) or client (%p)",
@ -341,9 +252,10 @@ status_t SurfaceControl::validate(per_client_cblk_t const* cblk) const
mToken, mIdentity, err, strerror(-err));
return err;
}
if (mIdentity != uint32_t(cblk->layers[mToken].identity)) {
uint32_t identity = cblk->getIdentity(mToken);
if (mIdentity != identity) {
LOGE("using an invalid surface id=%d, identity=%u should be %d",
mToken, mIdentity, cblk->layers[mToken].identity);
mToken, mIdentity, identity);
return NO_INIT;
}
return NO_ERROR;
@ -398,14 +310,17 @@ Surface::Surface(const sp<SurfaceControl>& surface)
: mClient(surface->mClient), mSurface(surface->mSurface),
mToken(surface->mToken), mIdentity(surface->mIdentity),
mFormat(surface->mFormat), mFlags(surface->mFlags),
mBufferMapper(BufferMapper::get()),
mBufferMapper(BufferMapper::get()), mSharedBufferClient(NULL),
mWidth(surface->mWidth), mHeight(surface->mHeight)
{
mSharedBufferClient = new SharedBufferClient(
mClient->mControl, mToken, 2);
init();
}
Surface::Surface(const Parcel& parcel)
: mBufferMapper(BufferMapper::get())
: mBufferMapper(BufferMapper::get()), mSharedBufferClient(NULL)
{
sp<IBinder> clientBinder = parcel.readStrongBinder();
mSurface = interface_cast<ISurface>(parcel.readStrongBinder());
@ -416,9 +331,14 @@ Surface::Surface(const Parcel& parcel)
mFormat = parcel.readInt32();
mFlags = parcel.readInt32();
if (clientBinder != NULL)
// FIXME: what does that mean if clientBinder is NULL here?
if (clientBinder != NULL) {
mClient = SurfaceComposerClient::clientForConnection(clientBinder);
mSharedBufferClient = new SharedBufferClient(
mClient->mControl, mToken, 2);
}
init();
}
@ -442,6 +362,7 @@ void Surface::init()
// be default we request a hardware surface
mUsage = GRALLOC_USAGE_HW_RENDER;
mUsageChanged = true;
mNeedFullUpdate = false;
}
Surface::~Surface()
@ -458,6 +379,7 @@ Surface::~Surface()
// happen without delay, since these resources are quite heavy.
mClient.clear();
mSurface.clear();
delete mSharedBufferClient;
IPCThreadState::self()->flushCommands();
}
@ -473,7 +395,7 @@ bool Surface::isValid() {
return mToken>=0 && mClient!=0;
}
status_t Surface::validate(per_client_cblk_t const* cblk) const
status_t Surface::validate(SharedClient const* cblk) const
{
sp<SurfaceComposerClient> client(getClient());
if (mToken<0 || mClient==0) {
@ -491,9 +413,10 @@ status_t Surface::validate(per_client_cblk_t const* cblk) const
mToken, mIdentity, err, strerror(-err));
return err;
}
if (mIdentity != uint32_t(cblk->layers[mToken].identity)) {
uint32_t identity = cblk->getIdentity(mToken);
if (mIdentity != identity) {
LOGE("using an invalid surface id=%d, identity=%u should be %d",
mToken, mIdentity, cblk->layers[mToken].identity);
mToken, mIdentity, identity);
return NO_INIT;
}
return NO_ERROR;
@ -511,42 +434,36 @@ bool Surface::isSameSurface(
// ----------------------------------------------------------------------------
int Surface::setSwapInterval(android_native_window_t* window, int interval)
{
int Surface::setSwapInterval(android_native_window_t* window, int interval) {
return 0;
}
int Surface::dequeueBuffer(android_native_window_t* window,
android_native_buffer_t** buffer)
{
android_native_buffer_t** buffer) {
Surface* self = getSelf(window);
return self->dequeueBuffer(buffer);
}
int Surface::lockBuffer(android_native_window_t* window,
android_native_buffer_t* buffer)
{
android_native_buffer_t* buffer) {
Surface* self = getSelf(window);
return self->lockBuffer(buffer);
}
int Surface::queueBuffer(android_native_window_t* window,
android_native_buffer_t* buffer)
{
android_native_buffer_t* buffer) {
Surface* self = getSelf(window);
return self->queueBuffer(buffer);
}
int Surface::query(android_native_window_t* window,
int what, int* value)
{
int what, int* value) {
Surface* self = getSelf(window);
return self->query(what, value);
}
int Surface::perform(android_native_window_t* window,
int operation, ...)
{
int operation, ...) {
va_list args;
va_start(args, operation);
Surface* self = getSelf(window);
@ -557,8 +474,7 @@ int Surface::perform(android_native_window_t* window,
// ----------------------------------------------------------------------------
status_t Surface::dequeueBuffer(sp<SurfaceBuffer>* buffer)
{
status_t Surface::dequeueBuffer(sp<SurfaceBuffer>* buffer) {
android_native_buffer_t* out;
status_t err = dequeueBuffer(&out);
if (err == NO_ERROR) {
@ -567,70 +483,49 @@ status_t Surface::dequeueBuffer(sp<SurfaceBuffer>* buffer)
return err;
}
status_t Surface::lockBuffer(const sp<SurfaceBuffer>& buffer)
{
return lockBuffer(buffer.get());
}
status_t Surface::queueBuffer(const sp<SurfaceBuffer>& buffer)
{
return queueBuffer(buffer.get());
}
// ----------------------------------------------------------------------------
int Surface::dequeueBuffer(android_native_buffer_t** buffer)
{
// FIXME: dequeueBuffer() needs proper implementation
Mutex::Autolock _l(mSurfaceLock);
sp<SurfaceComposerClient> client(getClient());
per_client_cblk_t* const cblk = client->mControl;
status_t err = validate(cblk);
status_t err = validate(client->mControl);
if (err != NO_ERROR)
return err;
SurfaceID index(mToken);
int32_t backIdx = cblk->lock_layer(size_t(index),
per_client_cblk_t::BLOCKING);
if (backIdx < 0)
return status_t(backIdx);
mBackbufferIndex = backIdx;
layer_cblk_t* const lcblk = &(cblk->layers[index]);
volatile const surface_info_t* const back = lcblk->surface + backIdx;
const sp<SurfaceBuffer>& backBuffer(mBuffers[backIdx]);
if (backBuffer==0 &&
!((back->flags & surface_info_t::eNeedNewBuffer) || mUsageChanged)) {
LOGW("dequeueBuffer: backbuffer is null, but eNeedNewBuffer "
"is not set, fetching a buffer anyways...");
ssize_t bufIdx = mSharedBufferClient->dequeue();
if (bufIdx < 0) {
LOGE("error dequeuing a buffer (%s)", strerror(bufIdx));
return bufIdx;
}
if ((back->flags & surface_info_t::eNeedNewBuffer) ||mUsageChanged ||
backBuffer==0)
{
mUsageChanged = false;
err = getBufferLocked(backIdx, mUsage);
// FIXME: in case of failure below, we need to undo the dequeue
uint32_t usage;
const bool usageChanged = getUsage(&usage);
const sp<SurfaceBuffer>& backBuffer(mBuffers[bufIdx]);
if ((backBuffer == 0) || usageChanged ||
mSharedBufferClient->needNewBuffer(bufIdx)) {
err = getBufferLocked(bufIdx, usage);
LOGE_IF(err, "getBufferLocked(%ld, %08x) failed (%s)",
bufIdx, usage, strerror(-err));
if (err == NO_ERROR) {
// reset the width/height with the what we get from the buffer
const sp<SurfaceBuffer>& backBuffer(mBuffers[backIdx]);
mWidth = uint32_t(backBuffer->width);
mHeight = uint32_t(backBuffer->height);
}
}
// if we still don't have a buffer here, we probably ran out of memory
if (!err && backBuffer==0) {
err = NO_MEMORY;
}
if (err == NO_ERROR) {
if (backBuffer != 0) {
mDirtyRegion.set(backBuffer->width, backBuffer->height);
*buffer = backBuffer.get();
} else {
err = NO_MEMORY;
}
mDirtyRegion.set(backBuffer->width, backBuffer->height);
*buffer = backBuffer.get();
} else {
mSharedBufferClient->undoDequeue(bufIdx);
}
return err;
@ -638,25 +533,21 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer)
int Surface::lockBuffer(android_native_buffer_t* buffer)
{
Mutex::Autolock _l(mSurfaceLock);
sp<SurfaceComposerClient> client(getClient());
per_client_cblk_t* const cblk = client->mControl;
status_t err = validate(cblk);
status_t err = validate(client->mControl);
if (err != NO_ERROR)
return err;
// FIXME: lockBuffer() needs proper implementation
return 0;
int32_t bufIdx = SurfaceBuffer::getSelf(buffer)->getIndex();
err = mSharedBufferClient->lock(bufIdx);
LOGE_IF(err, "error locking buffer %d (%s)", bufIdx, strerror(-err));
return err;
}
int Surface::queueBuffer(android_native_buffer_t* buffer)
{
Mutex::Autolock _l(mSurfaceLock);
sp<SurfaceComposerClient> client(getClient());
per_client_cblk_t* const cblk = client->mControl;
status_t err = validate(cblk);
status_t err = validate(client->mControl);
if (err != NO_ERROR)
return err;
@ -664,30 +555,30 @@ int Surface::queueBuffer(android_native_buffer_t* buffer)
mDirtyRegion.set(mSwapRectangle);
}
// transmit the dirty region
SurfaceID index(mToken);
layer_cblk_t* const lcblk = &(cblk->layers[index]);
_send_dirty_region(lcblk, mDirtyRegion);
int32_t bufIdx = SurfaceBuffer::getSelf(buffer)->getIndex();
mSharedBufferClient->setDirtyRegion(bufIdx, mDirtyRegion);
err = mSharedBufferClient->queue(bufIdx);
LOGE_IF(err, "error queuing buffer %d (%s)", bufIdx, strerror(-err));
uint32_t newstate = cblk->unlock_layer_and_post(size_t(index));
if (!(newstate & eNextFlipPending))
if (err == NO_ERROR) {
// FIXME: can we avoid this IPC if we know there is one pending?
client->signalServer();
return NO_ERROR;
}
return err;
}
int Surface::query(int what, int* value)
{
switch (what) {
case NATIVE_WINDOW_WIDTH:
*value = int(mWidth);
return NO_ERROR;
case NATIVE_WINDOW_HEIGHT:
*value = int(mHeight);
return NO_ERROR;
case NATIVE_WINDOW_FORMAT:
*value = int(mFormat);
return NO_ERROR;
case NATIVE_WINDOW_WIDTH:
*value = int(mWidth);
return NO_ERROR;
case NATIVE_WINDOW_HEIGHT:
*value = int(mHeight);
return NO_ERROR;
case NATIVE_WINDOW_FORMAT:
*value = int(mFormat);
return NO_ERROR;
}
return BAD_VALUE;
}
@ -715,6 +606,17 @@ void Surface::setUsage(uint32_t reqUsage)
}
}
bool Surface::getUsage(uint32_t* usage)
{
Mutex::Autolock _l(mSurfaceLock);
*usage = mUsage;
if (mUsageChanged) {
mUsageChanged = false;
return true;
}
return false;
}
// ----------------------------------------------------------------------------
status_t Surface::lock(SurfaceInfo* info, bool blocking) {
@ -723,43 +625,55 @@ status_t Surface::lock(SurfaceInfo* info, bool blocking) {
status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking)
{
if (mApiLock.tryLock() != NO_ERROR) {
LOGE("calling Surface::lock() from different threads!");
CallStack stack;
stack.update();
stack.dump("Surface::lock called from different threads");
return WOULD_BLOCK;
}
// we're intending to do software rendering from this point
setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
sp<SurfaceBuffer> backBuffer;
status_t err = dequeueBuffer(&backBuffer);
LOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
if (err == NO_ERROR) {
err = lockBuffer(backBuffer);
err = lockBuffer(backBuffer.get());
LOGE_IF(err, "lockBuffer (idx=%d) failed (%s)",
backBuffer->getIndex(), strerror(-err));
if (err == NO_ERROR) {
// we handle copy-back here...
const Rect bounds(backBuffer->width, backBuffer->height);
Region scratch(bounds);
Region& newDirtyRegion(dirtyIn ? *dirtyIn : scratch);
sp<SurfaceComposerClient> client(getClient());
per_client_cblk_t* const cblk = client->mControl;
layer_cblk_t* const lcblk = &(cblk->layers[SurfaceID(mToken)]);
volatile const surface_info_t* const back = lcblk->surface + mBackbufferIndex;
if (back->flags & surface_info_t::eBufferDirty) {
// content is meaningless in this case and the whole surface
// needs to be redrawn.
if (mNeedFullUpdate) {
// reset newDirtyRegion to bounds when a buffer is reallocated
// it would be better if this information was associated with
// the buffer and made available to outside of Surface.
// This will do for now though.
mNeedFullUpdate = false;
newDirtyRegion.set(bounds);
} else {
newDirtyRegion.andSelf(bounds);
const sp<SurfaceBuffer>& frontBuffer(mBuffers[1-mBackbufferIndex]);
if (frontBuffer !=0 &&
backBuffer->width == frontBuffer->width &&
backBuffer->height == frontBuffer->height &&
!(lcblk->flags & eNoCopyBack))
{
const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));
if (!copyback.isEmpty() && frontBuffer!=0) {
// copy front to back
copyBlt(backBuffer, frontBuffer, copyback);
}
}
const sp<SurfaceBuffer>& frontBuffer(mPostedBuffer);
if (frontBuffer !=0 &&
backBuffer->width == frontBuffer->width &&
backBuffer->height == frontBuffer->height &&
!(mFlags & ISurfaceComposer::eDestroyBackbuffer))
{
const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));
if (!copyback.isEmpty() && frontBuffer!=0) {
// copy front to back
copyBlt(backBuffer, frontBuffer, copyback);
}
}
mDirtyRegion = newDirtyRegion;
mOldDirtyRegion = newDirtyRegion;
@ -768,8 +682,8 @@ status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking)
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
newDirtyRegion.bounds(), &vaddr);
LOGW_IF(res, "failed locking buffer %d (%p)",
mBackbufferIndex, backBuffer->handle);
LOGW_IF(res, "failed locking buffer (handle = %p)",
backBuffer->handle);
mLockedBuffer = backBuffer;
other->w = backBuffer->width;
@ -780,36 +694,29 @@ status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking)
other->bits = vaddr;
}
}
mApiLock.unlock();
return err;
}
status_t Surface::unlockAndPost()
{
if (mLockedBuffer == 0)
if (mLockedBuffer == 0) {
LOGE("unlockAndPost failed, no locked buffer");
return BAD_VALUE;
}
status_t res = mLockedBuffer->unlock();
LOGW_IF(res, "failed unlocking buffer %d (%p)",
mBackbufferIndex, mLockedBuffer->handle);
status_t err = mLockedBuffer->unlock();
LOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
status_t err = queueBuffer(mLockedBuffer);
err = queueBuffer(mLockedBuffer.get());
LOGE_IF(err, "queueBuffer (idx=%d) failed (%s)",
mLockedBuffer->getIndex(), strerror(-err));
mPostedBuffer = mLockedBuffer;
mLockedBuffer = 0;
return err;
}
void Surface::_send_dirty_region(
layer_cblk_t* lcblk, const Region& dirty)
{
const int32_t index = (lcblk->flags & eBufferIndex) >> eBufferIndexShift;
flat_region_t* flat_region = lcblk->region + index;
status_t err = dirty.write(flat_region, sizeof(flat_region_t));
if (err < NO_ERROR) {
// region doesn't fit, use the bounds
const Region reg(dirty.bounds());
reg.write(flat_region, sizeof(flat_region_t));
}
}
void Surface::setSwapRectangle(const Rect& r) {
Mutex::Autolock _l(mSurfaceLock);
mSwapRectangle = r;
@ -829,15 +736,22 @@ status_t Surface::getBufferLocked(int index, int usage)
currentBuffer.clear();
}
sp<SurfaceBuffer> buffer = s->getBuffer(usage);
LOGE_IF(buffer==0, "ISurface::getBuffer() returned NULL");
sp<SurfaceBuffer> buffer = s->requestBuffer(index, usage);
LOGE_IF(buffer==0,
"ISurface::getBuffer(%d, %08x) returned NULL",
index, usage);
if (buffer != 0) { // this should never happen by construction
LOGE_IF(buffer->handle == NULL,
"requestBuffer(%d, %08x) returned a buffer with a null handle",
index, usage);
if (buffer->handle != NULL) {
err = getBufferMapper().registerBuffer(buffer->handle);
LOGW_IF(err, "registerBuffer(...) failed %d (%s)",
err, strerror(-err));
if (err == NO_ERROR) {
currentBuffer = buffer;
currentBuffer->setIndex(index);
mNeedFullUpdate = true;
}
}
}

134
libs/ui/SurfaceBuffer.cpp Normal file
View File

@ -0,0 +1,134 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "SurfaceBuffer"
#include <stdint.h>
#include <errno.h>
#include <sys/types.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <binder/Parcel.h>
#include <ui/BufferMapper.h>
#include <ui/Rect.h>
#include <private/ui/SurfaceBuffer.h>
namespace android {
// ============================================================================
// SurfaceBuffer
// ============================================================================
SurfaceBuffer::SurfaceBuffer()
: BASE(), mOwner(false), mBufferMapper(BufferMapper::get()), mIndex(-1)
{
width =
height =
stride =
format =
usage = 0;
handle = NULL;
}
SurfaceBuffer::SurfaceBuffer(const Parcel& data)
: BASE(), mOwner(true), mBufferMapper(BufferMapper::get())
{
// we own the handle in this case
width = data.readInt32();
if (width < 0) {
width = height = stride = format = usage = 0;
handle = 0;
} else {
height = data.readInt32();
stride = data.readInt32();
format = data.readInt32();
usage = data.readInt32();
handle = data.readNativeHandle();
}
}
SurfaceBuffer::~SurfaceBuffer()
{
if (handle && mOwner) {
native_handle_close(handle);
native_handle_delete(const_cast<native_handle*>(handle));
}
}
status_t SurfaceBuffer::lock(uint32_t usage, void** vaddr)
{
const Rect lockBounds(width, height);
status_t res = lock(usage, lockBounds, vaddr);
return res;
}
status_t SurfaceBuffer::lock(uint32_t usage, const Rect& rect, void** vaddr)
{
if (rect.left < 0 || rect.right > this->width ||
rect.top < 0 || rect.bottom > this->height) {
LOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)",
rect.left, rect.top, rect.right, rect.bottom,
this->width, this->height);
return BAD_VALUE;
}
status_t res = getBufferMapper().lock(handle, usage, rect, vaddr);
return res;
}
status_t SurfaceBuffer::unlock()
{
status_t res = getBufferMapper().unlock(handle);
return res;
}
status_t SurfaceBuffer::writeToParcel(Parcel* reply,
android_native_buffer_t const* buffer)
{
if (buffer == NULL)
return BAD_VALUE;
if (buffer->width < 0 || buffer->height < 0)
return BAD_VALUE;
status_t err = NO_ERROR;
if (buffer->handle == NULL) {
// this buffer doesn't have a handle
reply->writeInt32(NO_MEMORY);
} else {
reply->writeInt32(buffer->width);
reply->writeInt32(buffer->height);
reply->writeInt32(buffer->stride);
reply->writeInt32(buffer->format);
reply->writeInt32(buffer->usage);
err = reply->writeNativeHandle(buffer->handle);
}
return err;
}
void SurfaceBuffer::setIndex(int index) {
mIndex = index;
}
int SurfaceBuffer::getIndex() const {
return mIndex;
}
}; // namespace android

View File

@ -40,8 +40,8 @@
#include <ui/SurfaceComposerClient.h>
#include <ui/Rect.h>
#include <private/ui/SharedState.h>
#include <private/ui/LayerState.h>
#include <private/ui/SharedBufferStack.h>
#include <private/ui/SurfaceFlingerSynchro.h>
#define VERBOSE(...) ((void)0)
@ -103,169 +103,6 @@ static volatile surface_flinger_cblk_t const * get_cblk()
// ---------------------------------------------------------------------------
// these functions are used by the clients
status_t per_client_cblk_t::validate(size_t i) const {
if (uint32_t(i) >= NUM_LAYERS_MAX)
return BAD_INDEX;
if (layers[i].swapState & eInvalidSurface)
return NO_MEMORY;
return NO_ERROR;
}
int32_t per_client_cblk_t::lock_layer(size_t i, uint32_t flags)
{
int32_t index;
uint32_t state;
int timeout = 0;
status_t result;
layer_cblk_t * const layer = layers + i;
const bool blocking = flags & BLOCKING;
const bool inspect = flags & INSPECT;
do {
state = layer->swapState;
if (UNLIKELY((state&(eFlipRequested|eNextFlipPending)) == eNextFlipPending)) {
LOGE("eNextFlipPending set but eFlipRequested not set, "
"layer=%d (lcblk=%p), state=%08x",
int(i), layer, int(state));
return INVALID_OPERATION;
}
if (UNLIKELY(state&eLocked)) {
LOGE("eLocked set when entering lock_layer(), "
"layer=%d (lcblk=%p), state=%08x",
int(i), layer, int(state));
return WOULD_BLOCK;
}
if (state & (eFlipRequested | eNextFlipPending | eResizeRequested
| eInvalidSurface))
{
int32_t resizeIndex;
Mutex::Autolock _l(lock);
// might block for a very short amount of time
// will never cause the server to block (trylock())
goto start_loop_here;
// We block the client if:
// eNextFlipPending: we've used both buffers already, so we need to
// wait for one to become availlable.
// eResizeRequested: the buffer we're going to acquire is being
// resized. Block until it is done.
// eFlipRequested && eBusy: the buffer we're going to acquire is
// currently in use by the server.
// eInvalidSurface: this is a special case, we don't block in this
// case, we just return an error.
while((state & (eNextFlipPending|eInvalidSurface)) ||
(state & ((resizeIndex) ? eResizeBuffer1 : eResizeBuffer0)) ||
((state & (eFlipRequested|eBusy)) == (eFlipRequested|eBusy)) )
{
if (state & eInvalidSurface)
return NO_MEMORY;
if (!blocking)
return WOULD_BLOCK;
timeout = 0;
result = cv.waitRelative(lock, seconds(1));
if (__builtin_expect(result!=NO_ERROR, false)) {
const int newState = layer->swapState;
LOGW( "lock_layer timed out (is the CPU pegged?) "
"layer=%d, lcblk=%p, state=%08x (was %08x)",
int(i), layer, newState, int(state));
timeout = newState != int(state);
}
start_loop_here:
state = layer->swapState;
resizeIndex = (state&eIndex) ^ ((state&eFlipRequested)>>1);
}
LOGW_IF(timeout,
"lock_layer() timed out but didn't appear to need "
"to be locked and we recovered "
"(layer=%d, lcblk=%p, state=%08x)",
int(i), layer, int(state));
}
// eFlipRequested is not set and cannot be set by another thread: it's
// safe to use the first buffer without synchronization.
// Choose the index depending on eFlipRequested.
// When it's set, choose the 'other' buffer.
index = (state&eIndex) ^ ((state&eFlipRequested)>>1);
// make sure this buffer is valid
status_t err = layer->surface[index].status;
if (err < 0) {
return err;
}
if (inspect) {
// we just want to inspect this layer. don't lock it.
goto done;
}
// last thing before we're done, we need to atomically lock the state
} while (android_atomic_cmpxchg(state, state|eLocked, &(layer->swapState)));
VERBOSE("locked layer=%d (lcblk=%p), buffer=%d, state=0x%08x",
int(i), layer, int(index), int(state));
// store the index of the locked buffer (for client use only)
layer->flags &= ~eBufferIndex;
layer->flags |= ((index << eBufferIndexShift) & eBufferIndex);
done:
return index;
}
uint32_t per_client_cblk_t::unlock_layer_and_post(size_t i)
{
// atomically set eFlipRequested and clear eLocked and optionally
// set eNextFlipPending if eFlipRequested was already set
layer_cblk_t * const layer = layers + i;
int32_t oldvalue, newvalue;
do {
oldvalue = layer->swapState;
// get current value
newvalue = oldvalue & ~eLocked;
// clear eLocked
newvalue |= eFlipRequested;
// set eFlipRequested
if (oldvalue & eFlipRequested)
newvalue |= eNextFlipPending;
// if eFlipRequested was already set, set eNextFlipPending
} while (android_atomic_cmpxchg(oldvalue, newvalue, &(layer->swapState)));
VERBOSE("request pageflip for layer=%d, buffer=%d, state=0x%08x",
int(i), int((layer->flags & eBufferIndex) >> eBufferIndexShift),
int(newvalue));
// from this point, the server can kick in at any time and use the first
// buffer, so we cannot use it anymore, and we must use the 'other'
// buffer instead (or wait if it is not available yet, see lock_layer).
return newvalue;
}
void per_client_cblk_t::unlock_layer(size_t i)
{
layer_cblk_t * const layer = layers + i;
android_atomic_and(~eLocked, &layer->swapState);
}
// ---------------------------------------------------------------------------
static inline int compare_type( const layer_state_t& lhs,
const layer_state_t& rhs) {
if (lhs.surface < rhs.surface) return -1;
@ -315,7 +152,7 @@ void SurfaceComposerClient::_init(
mControlMemory = mClient->getControlBlock();
mSignalServer = new SurfaceFlingerSynchro(sm);
mControl = static_cast<per_client_cblk_t *>(mControlMemory->getBase());
mControl = static_cast<SharedClient *>(mControlMemory->getBase());
}
SurfaceComposerClient::~SurfaceComposerClient()
@ -539,18 +376,17 @@ void SurfaceComposerClient::closeGlobalTransaction()
const size_t N = clients.size();
VERBOSE("closeGlobalTransaction (%ld clients)", N);
if (N == 1) {
clients[0]->closeTransaction();
} else {
const sp<ISurfaceComposer>& sm(_get_surface_manager());
sm->openGlobalTransaction();
for (size_t i=0; i<N; i++) {
clients[i]->closeTransaction();
}
sm->closeGlobalTransaction();
const sp<ISurfaceComposer>& sm(_get_surface_manager());
sm->openGlobalTransaction();
for (size_t i=0; i<N; i++) {
clients[i]->closeTransaction();
}
sm->closeGlobalTransaction();
}
status_t SurfaceComposerClient::freezeDisplay(DisplayID dpy, uint32_t flags)
{
const sp<ISurfaceComposer>& sm(_get_surface_manager());