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:
@ -25,8 +25,6 @@
|
||||
#include <ui/ISurfaceFlingerClient.h>
|
||||
#include <ui/Region.h>
|
||||
|
||||
#include <private/ui/SharedState.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
class Parcel;
|
||||
|
327
include/private/ui/SharedBufferStack.h
Normal file
327
include/private/ui/SharedBufferStack.h
Normal 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 */
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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 \
|
||||
|
@ -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
|
@ -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
|
@ -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));
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include "Buffer.h"
|
||||
#include "BufferAllocator.h"
|
||||
#include "LayerDim.h"
|
||||
#include "SurfaceFlinger.h"
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -23,7 +23,9 @@ LOCAL_SRC_FILES:= \
|
||||
PixelFormat.cpp \
|
||||
Rect.cpp \
|
||||
Region.cpp \
|
||||
SharedBufferStack.cpp \
|
||||
Surface.cpp \
|
||||
SurfaceBuffer.cpp \
|
||||
SurfaceComposerClient.cpp \
|
||||
SurfaceFlingerSynchro.cpp
|
||||
|
||||
|
@ -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: {
|
||||
|
352
libs/ui/SharedBufferStack.cpp
Normal file
352
libs/ui/SharedBufferStack.cpp
Normal 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
|
@ -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
134
libs/ui/SurfaceBuffer.cpp
Normal 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
|
||||
|
@ -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());
|
||||
|
Reference in New Issue
Block a user