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/ISurfaceFlingerClient.h>
|
||||||
#include <ui/Region.h>
|
#include <ui/Region.h>
|
||||||
|
|
||||||
#include <private/ui/SharedState.h>
|
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
|
|
||||||
class Parcel;
|
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 lock(uint32_t usage, const Rect& rect, void** vaddr);
|
||||||
status_t unlock();
|
status_t unlock();
|
||||||
|
|
||||||
|
void setIndex(int index);
|
||||||
|
int getIndex() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SurfaceBuffer();
|
SurfaceBuffer();
|
||||||
SurfaceBuffer(const Parcel& reply);
|
SurfaceBuffer(const Parcel& reply);
|
||||||
@@ -69,6 +72,7 @@ private:
|
|||||||
android_native_buffer_t const* buffer);
|
android_native_buffer_t const* buffer);
|
||||||
|
|
||||||
BufferMapper& mBufferMapper;
|
BufferMapper& mBufferMapper;
|
||||||
|
int mIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
}; // namespace android
|
}; // namespace android
|
||||||
|
|||||||
@@ -44,13 +44,13 @@ protected:
|
|||||||
UNREGISTER_BUFFERS,
|
UNREGISTER_BUFFERS,
|
||||||
POST_BUFFER, // one-way transaction
|
POST_BUFFER, // one-way transaction
|
||||||
CREATE_OVERLAY,
|
CREATE_OVERLAY,
|
||||||
GET_BUFFER,
|
REQUEST_BUFFER,
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DECLARE_META_INTERFACE(Surface);
|
DECLARE_META_INTERFACE(Surface);
|
||||||
|
|
||||||
virtual sp<SurfaceBuffer> getBuffer(int usage) = 0;
|
virtual sp<SurfaceBuffer> requestBuffer(int bufferIdx, int usage) = 0;
|
||||||
|
|
||||||
class BufferHeap {
|
class BufferHeap {
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ class IOMX;
|
|||||||
class Rect;
|
class Rect;
|
||||||
class Surface;
|
class Surface;
|
||||||
class SurfaceComposerClient;
|
class SurfaceComposerClient;
|
||||||
struct per_client_cblk_t;
|
class SharedClient;
|
||||||
struct layer_cblk_t;
|
class SharedBufferClient;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -109,7 +109,7 @@ private:
|
|||||||
|
|
||||||
~SurfaceControl();
|
~SurfaceControl();
|
||||||
|
|
||||||
status_t validate(per_client_cblk_t const* cblk) const;
|
status_t validate(SharedClient const* cblk) const;
|
||||||
void destroy();
|
void destroy();
|
||||||
|
|
||||||
sp<SurfaceComposerClient> mClient;
|
sp<SurfaceComposerClient> mClient;
|
||||||
@@ -190,8 +190,7 @@ private:
|
|||||||
|
|
||||||
status_t getBufferLocked(int index, int usage);
|
status_t getBufferLocked(int index, int usage);
|
||||||
|
|
||||||
status_t validate(per_client_cblk_t const* cblk) const;
|
status_t validate(SharedClient const* cblk) const;
|
||||||
static void _send_dirty_region(layer_cblk_t* lcblk, const Region& dirty);
|
|
||||||
|
|
||||||
inline const BufferMapper& getBufferMapper() const { return mBufferMapper; }
|
inline const BufferMapper& getBufferMapper() const { return mBufferMapper; }
|
||||||
inline BufferMapper& getBufferMapper() { return mBufferMapper; }
|
inline BufferMapper& getBufferMapper() { return mBufferMapper; }
|
||||||
@@ -210,11 +209,10 @@ private:
|
|||||||
int perform(int operation, va_list args);
|
int perform(int operation, va_list args);
|
||||||
|
|
||||||
status_t dequeueBuffer(sp<SurfaceBuffer>* buffer);
|
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);
|
void setUsage(uint32_t reqUsage);
|
||||||
|
bool getUsage(uint32_t* usage);
|
||||||
|
|
||||||
// constants
|
// constants
|
||||||
sp<SurfaceComposerClient> mClient;
|
sp<SurfaceComposerClient> mClient;
|
||||||
@@ -224,21 +222,23 @@ private:
|
|||||||
PixelFormat mFormat;
|
PixelFormat mFormat;
|
||||||
uint32_t mFlags;
|
uint32_t mFlags;
|
||||||
BufferMapper& mBufferMapper;
|
BufferMapper& mBufferMapper;
|
||||||
|
SharedBufferClient* mSharedBufferClient;
|
||||||
|
|
||||||
// protected by mSurfaceLock
|
// protected by mSurfaceLock
|
||||||
Rect mSwapRectangle;
|
Rect mSwapRectangle;
|
||||||
uint32_t mUsage;
|
uint32_t mUsage;
|
||||||
bool mUsageChanged;
|
int32_t mUsageChanged;
|
||||||
|
|
||||||
// protected by mSurfaceLock. These are also used from lock/unlock
|
// protected by mSurfaceLock. These are also used from lock/unlock
|
||||||
// but in that case, they must be called form the same thread.
|
// but in that case, they must be called form the same thread.
|
||||||
sp<SurfaceBuffer> mBuffers[2];
|
sp<SurfaceBuffer> mBuffers[2];
|
||||||
mutable Region mDirtyRegion;
|
mutable Region mDirtyRegion;
|
||||||
mutable uint8_t mBackbufferIndex;
|
|
||||||
|
|
||||||
// must be used from the lock/unlock thread
|
// must be used from the lock/unlock thread
|
||||||
sp<SurfaceBuffer> mLockedBuffer;
|
sp<SurfaceBuffer> mLockedBuffer;
|
||||||
|
sp<SurfaceBuffer> mPostedBuffer;
|
||||||
mutable Region mOldDirtyRegion;
|
mutable Region mOldDirtyRegion;
|
||||||
|
bool mNeedFullUpdate;
|
||||||
|
|
||||||
// query() must be called from dequeueBuffer() thread
|
// query() must be called from dequeueBuffer() thread
|
||||||
uint32_t mWidth;
|
uint32_t mWidth;
|
||||||
@@ -246,6 +246,7 @@ private:
|
|||||||
|
|
||||||
// Inherently thread-safe
|
// Inherently thread-safe
|
||||||
mutable Mutex mSurfaceLock;
|
mutable Mutex mSurfaceLock;
|
||||||
|
mutable Mutex mApiLock;
|
||||||
};
|
};
|
||||||
|
|
||||||
}; // namespace android
|
}; // namespace android
|
||||||
|
|||||||
@@ -21,7 +21,6 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include <utils/SortedVector.h>
|
#include <utils/SortedVector.h>
|
||||||
#include <utils/KeyedVector.h>
|
|
||||||
#include <utils/RefBase.h>
|
#include <utils/RefBase.h>
|
||||||
#include <utils/threads.h>
|
#include <utils/threads.h>
|
||||||
|
|
||||||
@@ -36,8 +35,7 @@ namespace android {
|
|||||||
|
|
||||||
class Region;
|
class Region;
|
||||||
class SurfaceFlingerSynchro;
|
class SurfaceFlingerSynchro;
|
||||||
struct per_client_cblk_t;
|
class SharedClient;
|
||||||
struct layer_cblk_t;
|
|
||||||
|
|
||||||
class SurfaceComposerClient : virtual public RefBase
|
class SurfaceComposerClient : virtual public RefBase
|
||||||
{
|
{
|
||||||
@@ -63,12 +61,12 @@ public:
|
|||||||
|
|
||||||
//! Create a surface
|
//! Create a surface
|
||||||
sp<SurfaceControl> createSurface(
|
sp<SurfaceControl> createSurface(
|
||||||
int pid, //!< pid of the process the surfacec is for
|
int pid, // pid of the process the surface is for
|
||||||
DisplayID display, //!< Display to create this surface on
|
DisplayID display, // Display to create this surface on
|
||||||
uint32_t w, //!< width in pixel
|
uint32_t w, // width in pixel
|
||||||
uint32_t h, //!< height in pixel
|
uint32_t h, // height in pixel
|
||||||
PixelFormat format, //!< pixel-format desired
|
PixelFormat format, // pixel-format desired
|
||||||
uint32_t flags = 0 //!< usage flags
|
uint32_t flags = 0 // usage flags
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
@@ -148,7 +146,7 @@ private:
|
|||||||
// these don't need to be protected because they never change
|
// these don't need to be protected because they never change
|
||||||
// after assignment
|
// after assignment
|
||||||
status_t mStatus;
|
status_t mStatus;
|
||||||
per_client_cblk_t* mControl;
|
SharedClient* mControl;
|
||||||
sp<IMemoryHeap> mControlMemory;
|
sp<IMemoryHeap> mControlMemory;
|
||||||
sp<ISurfaceFlingerClient> mClient;
|
sp<ISurfaceFlingerClient> mClient;
|
||||||
SurfaceFlingerSynchro* mSignalServer;
|
SurfaceFlingerSynchro* mSignalServer;
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ enum {
|
|||||||
BAD_INDEX = -EOVERFLOW,
|
BAD_INDEX = -EOVERFLOW,
|
||||||
NOT_ENOUGH_DATA = -ENODATA,
|
NOT_ENOUGH_DATA = -ENODATA,
|
||||||
WOULD_BLOCK = -EWOULDBLOCK,
|
WOULD_BLOCK = -EWOULDBLOCK,
|
||||||
TIMED_OUT = -ETIME,
|
TIMED_OUT = -ETIMEDOUT,
|
||||||
UNKNOWN_TRANSACTION = -EBADMSG,
|
UNKNOWN_TRANSACTION = -EBADMSG,
|
||||||
#else
|
#else
|
||||||
BAD_INDEX = -E2BIG,
|
BAD_INDEX = -E2BIG,
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ LOCAL_SRC_FILES:= \
|
|||||||
DisplayHardware/DisplayHardware.cpp \
|
DisplayHardware/DisplayHardware.cpp \
|
||||||
DisplayHardware/DisplayHardwareBase.cpp \
|
DisplayHardware/DisplayHardwareBase.cpp \
|
||||||
BlurFilter.cpp.arm \
|
BlurFilter.cpp.arm \
|
||||||
|
Buffer.cpp \
|
||||||
BufferAllocator.cpp \
|
BufferAllocator.cpp \
|
||||||
Layer.cpp \
|
Layer.cpp \
|
||||||
LayerBase.cpp \
|
LayerBase.cpp \
|
||||||
LayerBuffer.cpp \
|
LayerBuffer.cpp \
|
||||||
LayerBlur.cpp \
|
LayerBlur.cpp \
|
||||||
LayerBitmap.cpp \
|
|
||||||
LayerDim.cpp \
|
LayerDim.cpp \
|
||||||
MessageQueue.cpp \
|
MessageQueue.cpp \
|
||||||
SurfaceFlinger.cpp \
|
SurfaceFlinger.cpp \
|
||||||
|
|||||||
@@ -27,8 +27,8 @@
|
|||||||
#include <ui/Surface.h>
|
#include <ui/Surface.h>
|
||||||
#include <pixelflinger/pixelflinger.h>
|
#include <pixelflinger/pixelflinger.h>
|
||||||
|
|
||||||
|
#include "Buffer.h"
|
||||||
#include "BufferAllocator.h"
|
#include "BufferAllocator.h"
|
||||||
#include "LayerBitmap.h"
|
|
||||||
#include "SurfaceFlinger.h"
|
#include "SurfaceFlinger.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -38,15 +38,16 @@ namespace android {
|
|||||||
// Buffer and implementation of android_native_buffer_t
|
// 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,
|
Buffer::Buffer(uint32_t w, uint32_t h, PixelFormat format,
|
||||||
uint32_t reqUsage, uint32_t flags)
|
uint32_t reqUsage, uint32_t flags)
|
||||||
: SurfaceBuffer(), mInitCheck(NO_INIT), mFlags(flags),
|
: SurfaceBuffer(), mInitCheck(NO_INIT), mVStride(0)
|
||||||
mVStride(0)
|
|
||||||
{
|
{
|
||||||
this->format = format;
|
mInitCheck = initSize(w, h, format, reqUsage, flags);
|
||||||
if (w>0 && h>0) {
|
|
||||||
mInitCheck = initSize(w, h, reqUsage);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer::~Buffer()
|
Buffer::~Buffer()
|
||||||
@@ -66,7 +67,19 @@ android_native_buffer_t* Buffer::getNativeBuffer() const
|
|||||||
return static_cast<android_native_buffer_t*>(const_cast<Buffer*>(this));
|
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;
|
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
|
// secure buffer, don't store it into the GPU
|
||||||
usage = BufferAllocator::USAGE_SW_READ_OFTEN |
|
usage = BufferAllocator::USAGE_SW_READ_OFTEN |
|
||||||
BufferAllocator::USAGE_SW_WRITE_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);
|
err = allocator.alloc(w, h, format, usage, &handle, &stride);
|
||||||
|
|
||||||
if (err == NO_ERROR) {
|
if (err == NO_ERROR) {
|
||||||
width = w;
|
this->width = w;
|
||||||
height = h;
|
this->height = h;
|
||||||
|
this->format = format;
|
||||||
mVStride = 0;
|
mVStride = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,78 +134,6 @@ status_t Buffer::lock(GGLSurface* sur, uint32_t usage)
|
|||||||
return res;
|
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
|
}; // namespace android
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
#include <pixelflinger/pixelflinger.h>
|
#include <pixelflinger/pixelflinger.h>
|
||||||
|
|
||||||
#include <private/ui/SharedState.h>
|
#include <private/ui/SharedBufferStack.h>
|
||||||
#include <private/ui/SurfaceBuffer.h>
|
#include <private/ui/SurfaceBuffer.h>
|
||||||
|
|
||||||
class copybit_image_t;
|
class copybit_image_t;
|
||||||
@@ -38,10 +38,6 @@ struct android_native_buffer_t;
|
|||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
class IMemory;
|
|
||||||
class LayerBitmap;
|
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
// Buffer
|
// Buffer
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
@@ -56,6 +52,8 @@ public:
|
|||||||
SECURE = 0x00000004
|
SECURE = 0x00000004
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Buffer();
|
||||||
|
|
||||||
// creates w * h buffer
|
// creates w * h buffer
|
||||||
Buffer(uint32_t w, uint32_t h, PixelFormat format,
|
Buffer(uint32_t w, uint32_t h, PixelFormat format,
|
||||||
uint32_t reqUsage, uint32_t flags = 0);
|
uint32_t reqUsage, uint32_t flags = 0);
|
||||||
@@ -74,6 +72,9 @@ public:
|
|||||||
|
|
||||||
android_native_buffer_t* getNativeBuffer() const;
|
android_native_buffer_t* getNativeBuffer() const;
|
||||||
|
|
||||||
|
status_t reallocate(uint32_t w, uint32_t h, PixelFormat f,
|
||||||
|
uint32_t reqUsage, uint32_t flags);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class LightRefBase<Buffer>;
|
friend class LightRefBase<Buffer>;
|
||||||
Buffer(const Buffer& rhs);
|
Buffer(const Buffer& rhs);
|
||||||
@@ -81,52 +82,11 @@ private:
|
|||||||
Buffer& operator = (const Buffer& rhs);
|
Buffer& operator = (const Buffer& rhs);
|
||||||
const Buffer& operator = (const Buffer& rhs) const;
|
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;
|
ssize_t mInitCheck;
|
||||||
uint32_t mFlags;
|
uint32_t mVStride;
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}; // namespace android
|
}; // namespace android
|
||||||
@@ -71,14 +71,23 @@ void BufferAllocator::dump(String8& result) const
|
|||||||
result.append(buffer);
|
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,
|
status_t BufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat format,
|
||||||
int usage, buffer_handle_t* handle, int32_t* stride)
|
int usage, buffer_handle_t* handle, int32_t* stride)
|
||||||
{
|
{
|
||||||
Mutex::Autolock _l(mLock);
|
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
|
// we have a h/w allocator and h/w buffer is requested
|
||||||
status_t err = mAllocDev->alloc(mAllocDev,
|
status_t err = mAllocDev->alloc(mAllocDev,
|
||||||
w, h, format, usage, handle, stride);
|
w, h, format, usage, handle, stride);
|
||||||
|
|
||||||
LOGW_IF(err, "alloc(%u, %u, %d, %08x, ...) failed %d (%s)",
|
LOGW_IF(err, "alloc(%u, %u, %d, %08x, ...) failed %d (%s)",
|
||||||
w, h, format, usage, err, strerror(-err));
|
w, h, format, usage, err, strerror(-err));
|
||||||
|
|
||||||
|
|||||||
@@ -46,22 +46,25 @@ using namespace android;
|
|||||||
static __attribute__((noinline))
|
static __attribute__((noinline))
|
||||||
void checkGLErrors()
|
void checkGLErrors()
|
||||||
{
|
{
|
||||||
GLenum error = glGetError();
|
do {
|
||||||
if (error != GL_NO_ERROR)
|
// there could be more than one error flag
|
||||||
|
GLenum error = glGetError();
|
||||||
|
if (error == GL_NO_ERROR)
|
||||||
|
break;
|
||||||
LOGE("GL error 0x%04x", int(error));
|
LOGE("GL error 0x%04x", int(error));
|
||||||
|
} while(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static __attribute__((noinline))
|
static __attribute__((noinline))
|
||||||
void checkEGLErrors(const char* token)
|
void checkEGLErrors(const char* token)
|
||||||
{
|
{
|
||||||
EGLint error = eglGetError();
|
EGLint error = eglGetError();
|
||||||
// GLESonGL seems to be returning 0 when there is no errors?
|
if (error && error != EGL_SUCCESS) {
|
||||||
if (error && error != EGL_SUCCESS)
|
LOGE("%s: EGL error 0x%04x (%s)",
|
||||||
LOGE("%s error 0x%04x (%s)",
|
|
||||||
token, int(error), EGLUtils::strerror(error));
|
token, int(error), EGLUtils::strerror(error));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the display to the specified values.
|
* Initialize the display to the specified values.
|
||||||
*
|
*
|
||||||
@@ -158,7 +161,6 @@ void DisplayHardware::init(uint32_t dpy)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL);
|
surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL);
|
||||||
checkEGLErrors("eglCreateWindowSurface");
|
|
||||||
|
|
||||||
if (eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &dummy) == EGL_TRUE) {
|
if (eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &dummy) == EGL_TRUE) {
|
||||||
if (dummy == EGL_BUFFER_PRESERVED) {
|
if (dummy == EGL_BUFFER_PRESERVED) {
|
||||||
@@ -212,8 +214,6 @@ void DisplayHardware::init(uint32_t dpy)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
context = eglCreateContext(display, config, NULL, NULL);
|
context = eglCreateContext(display, config, NULL, NULL);
|
||||||
//checkEGLErrors("eglCreateContext");
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Gather OpenGL ES extensions
|
* Gather OpenGL ES extensions
|
||||||
|
|||||||
@@ -28,9 +28,9 @@
|
|||||||
#include <ui/PixelFormat.h>
|
#include <ui/PixelFormat.h>
|
||||||
#include <ui/Surface.h>
|
#include <ui/Surface.h>
|
||||||
|
|
||||||
|
#include "Buffer.h"
|
||||||
#include "clz.h"
|
#include "clz.h"
|
||||||
#include "Layer.h"
|
#include "Layer.h"
|
||||||
#include "LayerBitmap.h"
|
|
||||||
#include "SurfaceFlinger.h"
|
#include "SurfaceFlinger.h"
|
||||||
#include "DisplayHardware/DisplayHardware.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)
|
Layer::Layer(SurfaceFlinger* flinger, DisplayID display,
|
||||||
: LayerBaseClient(flinger, display, c, i),
|
const sp<Client>& c, int32_t i)
|
||||||
|
: LayerBaseClient(flinger, display, c, i), lcblk(NULL),
|
||||||
mSecure(false),
|
mSecure(false),
|
||||||
mFrontBufferIndex(1),
|
mNeedsBlending(true)
|
||||||
mNeedsBlending(true),
|
|
||||||
mResizeTransactionDone(false)
|
|
||||||
{
|
{
|
||||||
// no OpenGL operation is possible here, since we might not be
|
// no OpenGL operation is possible here, since we might not be
|
||||||
// in the OpenGL thread.
|
// in the OpenGL thread.
|
||||||
|
lcblk = new SharedBufferServer(c->ctrlblk, i, NUM_BUFFERS);
|
||||||
|
mFrontBufferIndex = lcblk->getFrontBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
Layer::~Layer()
|
Layer::~Layer()
|
||||||
{
|
{
|
||||||
destroy();
|
destroy();
|
||||||
// the actual buffers will be destroyed here
|
// the actual buffers will be destroyed here
|
||||||
|
delete lcblk;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Layer::destroy()
|
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) {
|
if (mTextures[i].name != -1U) {
|
||||||
glDeleteTextures(1, &mTextures[i].name);
|
glDeleteTextures(1, &mTextures[i].name);
|
||||||
mTextures[i].name = -1U;
|
mTextures[i].name = -1U;
|
||||||
@@ -76,19 +79,11 @@ void Layer::destroy()
|
|||||||
eglDestroyImageKHR(dpy, mTextures[i].image);
|
eglDestroyImageKHR(dpy, mTextures[i].image);
|
||||||
mTextures[i].image = EGL_NO_IMAGE_KHR;
|
mTextures[i].image = EGL_NO_IMAGE_KHR;
|
||||||
}
|
}
|
||||||
mBuffers[i].free();
|
mBuffers[i].clear();
|
||||||
}
|
}
|
||||||
mSurface.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
|
sp<LayerBaseClient::Surface> Layer::createSurface() const
|
||||||
{
|
{
|
||||||
return mSurface;
|
return mSurface;
|
||||||
@@ -112,13 +107,14 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h,
|
|||||||
if (flags & ISurfaceComposer::eSecure)
|
if (flags & ISurfaceComposer::eSecure)
|
||||||
bufferFlags |= Buffer::SECURE;
|
bufferFlags |= Buffer::SECURE;
|
||||||
|
|
||||||
|
mFormat = format;
|
||||||
|
mWidth = w;
|
||||||
|
mHeight = h;
|
||||||
mSecure = (bufferFlags & Buffer::SECURE) ? true : false;
|
mSecure = (bufferFlags & Buffer::SECURE) ? true : false;
|
||||||
mNeedsBlending = (info.h_alpha - info.l_alpha) > 0;
|
mNeedsBlending = (info.h_alpha - info.l_alpha) > 0;
|
||||||
for (int i=0 ; i<2 ; i++) {
|
mBufferFlags = bufferFlags;
|
||||||
err = mBuffers[i].init(lcblk->surface + i, w, h, format, bufferFlags);
|
for (size_t i=0 ; i<NUM_BUFFERS ; i++) {
|
||||||
if (err != NO_ERROR) {
|
mBuffers[i] = new Buffer();
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
mSurface = new SurfaceLayer(mFlinger, clientIndex(), this);
|
mSurface = new SurfaceLayer(mFlinger, clientIndex(), this);
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
@@ -126,7 +122,8 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h,
|
|||||||
|
|
||||||
void Layer::reloadTexture(const Region& dirty)
|
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)) {
|
if (LIKELY(mFlags & DisplayHardware::DIRECT_TEXTURE)) {
|
||||||
int index = mFrontBufferIndex;
|
int index = mFrontBufferIndex;
|
||||||
if (LIKELY(!mTextures[index].dirty)) {
|
if (LIKELY(!mTextures[index].dirty)) {
|
||||||
@@ -202,193 +199,111 @@ void Layer::onDraw(const Region& clip) const
|
|||||||
const int index = (mFlags & DisplayHardware::DIRECT_TEXTURE) ?
|
const int index = (mFlags & DisplayHardware::DIRECT_TEXTURE) ?
|
||||||
mFrontBufferIndex : 0;
|
mFrontBufferIndex : 0;
|
||||||
GLuint textureName = mTextures[index].name;
|
GLuint textureName = mTextures[index].name;
|
||||||
|
|
||||||
if (UNLIKELY(textureName == -1LU)) {
|
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
|
// the texture has not been created yet, this Layer has
|
||||||
// in fact never been drawn into. this happens frequently with
|
// in fact never been drawn into. this happens frequently with
|
||||||
// SurfaceView.
|
// SurfaceView.
|
||||||
clearWithOpenGL(clip);
|
clearWithOpenGL(clip);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
drawWithOpenGL(clip, mTextures[index]);
|
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
|
* This is called from the client's Surface::dequeue(). This can happen
|
||||||
* the surface successfully. We're therefore guaranteed that the
|
* at any time, especially while we're in the middle of using the
|
||||||
* back-buffer is not in use by ourselves.
|
* buffer 'index' as our front buffer.
|
||||||
* 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?
|
* Make sure the buffer we're resizing is not the front buffer and has been
|
||||||
* - resize() form post()
|
* dequeued. Once this condition is asserted, we are guaranteed that this
|
||||||
* - resize() from doTransaction()
|
* buffer cannot become the front buffer under our feet, since we're called
|
||||||
*
|
* from Surface::dequeue()
|
||||||
* We'll probably need an internal lock for this.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* TODO: We need to make sure that post() doesn't swap
|
|
||||||
* the buffers under us.
|
|
||||||
*/
|
*/
|
||||||
|
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
|
Mutex::Autolock _l(mLock);
|
||||||
// backbuffer index, which cannot change (since the app has locked it).
|
uint32_t w = mWidth;
|
||||||
const uint32_t state = lcblk->swapState;
|
uint32_t h = mHeight;
|
||||||
const int32_t backBufferIndex = layer_cblk_t::backBuffer(state);
|
|
||||||
|
|
||||||
// get rid of the EGL image, since we shouldn't need it anymore
|
sp<Buffer>& buffer(mBuffers[index]);
|
||||||
// (note that we're in a different thread than where it is being used)
|
if (buffer->getStrongCount() == 1) {
|
||||||
if (mTextures[backBufferIndex].image != EGL_NO_IMAGE_KHR) {
|
err = buffer->reallocate(w, h, mFormat, usage, mBufferFlags);
|
||||||
EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
|
} else {
|
||||||
eglDestroyImageKHR(dpy, mTextures[backBufferIndex].image);
|
// here we have to reallocate a new buffer because we could have a
|
||||||
mTextures[backBufferIndex].image = EGL_NO_IMAGE_KHR;
|
// 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();
|
||||||
}
|
}
|
||||||
|
|
||||||
LayerBitmap& layerBitmap(mBuffers[backBufferIndex]);
|
if (err || buffer->handle == 0) {
|
||||||
sp<SurfaceBuffer> buffer = layerBitmap.allocate(usage);
|
LOGE_IF(err || buffer->handle == 0,
|
||||||
|
"Layer::requestBuffer(this=%p), index=%d, w=%d, h=%d failed (%s)",
|
||||||
LOGD_IF(DEBUG_RESIZE,
|
this, index, w, h, strerror(-err));
|
||||||
"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?
|
|
||||||
} else {
|
} 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...
|
// texture is now dirty...
|
||||||
mTextures[backBufferIndex].dirty = true;
|
mTextures[index].dirty = true;
|
||||||
// ... so it the visible region (because we consider the surface's
|
|
||||||
// buffer size for visibility calculations)
|
|
||||||
forceVisibilityTransaction();
|
|
||||||
mFlinger->setTransactionFlags(eTraversalNeeded);
|
|
||||||
}
|
}
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Layer::scheduleBroadcast()
|
|
||||||
{
|
|
||||||
sp<Client> ourClient(client.promote());
|
|
||||||
if (ourClient != 0) {
|
|
||||||
mFlinger->scheduleBroadcast(ourClient);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t Layer::doTransaction(uint32_t flags)
|
uint32_t Layer::doTransaction(uint32_t flags)
|
||||||
{
|
{
|
||||||
const Layer::State& front(drawingState());
|
const Layer::State& front(drawingState());
|
||||||
const Layer::State& temp(currentState());
|
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
|
// Index of the back buffer
|
||||||
const bool backbufferChanged = (front.w != temp.w) || (front.h != temp.h);
|
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,
|
LOGD_IF(DEBUG_RESIZE,
|
||||||
"resize (layer=%p), state=%08x, "
|
"resize (layer=%p), requested (%dx%d), "
|
||||||
"requested (%dx%d), "
|
"drawing (%d,%d), (%dx%d), (%dx%d)",
|
||||||
"drawing (%d,%d), "
|
this, int(temp.w), int(temp.h),
|
||||||
"index=%d, (%dx%d), (%dx%d)",
|
|
||||||
this, state,
|
|
||||||
int(temp.w), int(temp.h),
|
|
||||||
int(drawingState().w), int(drawingState().h),
|
int(drawingState().w), int(drawingState().h),
|
||||||
int(clientBackBufferIndex),
|
int(mBuffers[0]->getWidth()), int(mBuffers[0]->getHeight()),
|
||||||
int(mBuffers[0].getWidth()), int(mBuffers[0].getHeight()),
|
int(mBuffers[1]->getWidth()), int(mBuffers[1]->getHeight()));
|
||||||
int(mBuffers[1].getWidth()), int(mBuffers[1].getHeight()));
|
|
||||||
|
|
||||||
if (state & eLocked) {
|
// record the new size, form this point on, when the client request a
|
||||||
// if the buffer is locked, we can't resize anything because
|
// buffer, it'll get the new size.
|
||||||
// - the backbuffer is currently in use by the user
|
setDrawingSize(temp.w, temp.h);
|
||||||
// - 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;
|
|
||||||
|
|
||||||
// we're being resized and there is a freeze display request,
|
// all buffers need reallocation
|
||||||
// acquire a freeze lock, so that the screen stays put
|
lcblk->reallocate();
|
||||||
// until we've redrawn at the new size; this is to avoid
|
|
||||||
// glitches upon orientation changes.
|
// recompute the visible region
|
||||||
if (mFlinger->hasFreezeRequest()) {
|
// FIXME: ideally we would do that only when we have received
|
||||||
// if the surface is hidden, don't try to acquire the
|
// a buffer of the right size
|
||||||
// freeze lock, since hidden surfaces may never redraw
|
flags |= Layer::eVisibleRegion;
|
||||||
if (!(front.flags & ISurfaceComposer::eLayerHidden)) {
|
this->contentDirty = true;
|
||||||
mFreezeLock = mFlinger->getFreezeLock();
|
|
||||||
}
|
#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.sequence != front.sequence) {
|
||||||
@@ -402,65 +317,10 @@ uint32_t Layer::doTransaction(uint32_t flags)
|
|||||||
return LayerBase::doTransaction(flags);
|
return LayerBase::doTransaction(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t Layer::resize(
|
void Layer::setDrawingSize(uint32_t w, uint32_t h) {
|
||||||
int32_t clientBackBufferIndex,
|
Mutex::Autolock _l(mLock);
|
||||||
uint32_t width, uint32_t height,
|
mWidth = w;
|
||||||
const char* what)
|
mHeight = h;
|
||||||
{
|
|
||||||
/*
|
|
||||||
* 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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@@ -469,139 +329,26 @@ void Layer::setSizeChanged(uint32_t w, uint32_t h)
|
|||||||
|
|
||||||
void Layer::lockPageFlip(bool& recomputeVisibleRegions)
|
void Layer::lockPageFlip(bool& recomputeVisibleRegions)
|
||||||
{
|
{
|
||||||
uint32_t state = android_atomic_or(eBusy, &(lcblk->swapState));
|
ssize_t buf = lcblk->retireAndLock();
|
||||||
// preemptively block the client, because he might set
|
if (buf < NO_ERROR) {
|
||||||
// eFlipRequested at any time and want to use this buffer
|
//LOGW("nothing to retire (%s)", strerror(-buf));
|
||||||
// for the next frame. This will be unset below if it
|
// NOTE: here the buffer is locked because we will used
|
||||||
// turns out we didn't need it.
|
// for composition later in the loop
|
||||||
|
|
||||||
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();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UNLIKELY(state & eFlipRequested)) {
|
// we retired a buffer, which becomes the new front buffer
|
||||||
uint32_t oldState;
|
mFrontBufferIndex = buf;
|
||||||
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)
|
// get the dirty region
|
||||||
{
|
sp<Buffer> newFrontBuffer(getBuffer(buf));
|
||||||
// atomically swap buffers and (re)set eFlipRequested
|
const Region dirty(lcblk->getDirtyRegion(buf));
|
||||||
int32_t oldValue, newValue;
|
mPostedDirtyRegion = dirty.intersect( newFrontBuffer->getBounds() );
|
||||||
layer_cblk_t * const lcblk = this->lcblk;
|
|
||||||
do {
|
|
||||||
oldValue = lcblk->swapState;
|
|
||||||
// get the current value
|
|
||||||
|
|
||||||
LOG_ASSERT(oldValue&eFlipRequested,
|
// FIXME: signal an event if we have more buffers waiting
|
||||||
"eFlipRequested not set, yet we're flipping! (state=0x%08lx)",
|
// mFlinger->signalEvent();
|
||||||
long(oldValue));
|
|
||||||
|
|
||||||
newValue = (oldValue ^ eIndex);
|
reloadTexture( mPostedDirtyRegion );
|
||||||
// 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;
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
|
|
||||||
// ... post the new front-buffer
|
|
||||||
Region dirty(lcblk->region + index);
|
|
||||||
dirty.andSelf(frontBuffer().getBounds());
|
|
||||||
|
|
||||||
//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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Layer::unlockPageFlip(
|
void Layer::unlockPageFlip(
|
||||||
@@ -622,21 +369,15 @@ void Layer::unlockPageFlip(
|
|||||||
// is in screen space as well).
|
// is in screen space as well).
|
||||||
dirtyRegion.andSelf(visibleRegionScreen);
|
dirtyRegion.andSelf(visibleRegionScreen);
|
||||||
outDirtyRegion.orSelf(dirtyRegion);
|
outDirtyRegion.orSelf(dirtyRegion);
|
||||||
|
|
||||||
// client could be blocked, so signal them so they get a
|
|
||||||
// chance to reevaluate their condition.
|
|
||||||
scheduleBroadcast();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Layer::finishPageFlip()
|
void Layer::finishPageFlip()
|
||||||
{
|
{
|
||||||
if (LIKELY(!(lcblk->swapState & eInvalidSurface))) {
|
status_t err = lcblk->unlock( mFrontBufferIndex );
|
||||||
LOGE_IF(!(lcblk->swapState & eBusy),
|
LOGE_IF(err!=NO_ERROR,
|
||||||
"layer %p wasn't locked!", this);
|
"layer %p, buffer=%d wasn't locked!",
|
||||||
android_atomic_and(~eBusy, &(lcblk->swapState));
|
this, mFrontBufferIndex);
|
||||||
}
|
|
||||||
scheduleBroadcast();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -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());
|
sp<Layer> owner(getOwner());
|
||||||
if (owner != 0) {
|
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;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,10 +21,6 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include <ui/PixelFormat.h>
|
#include <ui/PixelFormat.h>
|
||||||
|
|
||||||
#include <private/ui/SharedState.h>
|
|
||||||
#include <private/ui/LayerState.h>
|
|
||||||
|
|
||||||
#include <pixelflinger/pixelflinger.h>
|
#include <pixelflinger/pixelflinger.h>
|
||||||
|
|
||||||
#include <EGL/egl.h>
|
#include <EGL/egl.h>
|
||||||
@@ -32,7 +28,7 @@
|
|||||||
#include <GLES/gl.h>
|
#include <GLES/gl.h>
|
||||||
#include <GLES/glext.h>
|
#include <GLES/glext.h>
|
||||||
|
|
||||||
#include "LayerBitmap.h"
|
#include "Buffer.h"
|
||||||
#include "LayerBase.h"
|
#include "LayerBase.h"
|
||||||
#include "Transform.h"
|
#include "Transform.h"
|
||||||
|
|
||||||
@@ -41,12 +37,12 @@ namespace android {
|
|||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
class Client;
|
class Client;
|
||||||
class LayerBitmap;
|
|
||||||
class FreezeLock;
|
class FreezeLock;
|
||||||
|
class Buffer;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
const int NUM_BUFFERS = 2;
|
const size_t NUM_BUFFERS = 2;
|
||||||
|
|
||||||
class Layer : public LayerBaseClient
|
class Layer : public LayerBaseClient
|
||||||
{
|
{
|
||||||
@@ -56,23 +52,22 @@ public:
|
|||||||
virtual char const* getTypeID() const { return typeID; }
|
virtual char const* getTypeID() const { return typeID; }
|
||||||
virtual uint32_t getTypeInfo() const { return typeInfo; }
|
virtual uint32_t getTypeInfo() const { return typeInfo; }
|
||||||
|
|
||||||
|
|
||||||
|
SharedBufferServer* lcblk;
|
||||||
|
|
||||||
|
|
||||||
Layer(SurfaceFlinger* flinger, DisplayID display,
|
Layer(SurfaceFlinger* flinger, DisplayID display,
|
||||||
const sp<Client>& client, int32_t i);
|
const sp<Client>& client, int32_t i);
|
||||||
|
|
||||||
virtual ~Layer();
|
virtual ~Layer();
|
||||||
|
|
||||||
inline PixelFormat pixelFormat() const {
|
status_t setBuffers(uint32_t w, uint32_t h,
|
||||||
return frontBuffer().getPixelFormat();
|
PixelFormat format, uint32_t flags=0);
|
||||||
}
|
|
||||||
|
|
||||||
status_t setBuffers( uint32_t w, uint32_t h,
|
void setDrawingSize(uint32_t w, uint32_t h);
|
||||||
PixelFormat format, uint32_t flags=0);
|
|
||||||
|
|
||||||
virtual void onDraw(const Region& clip) const;
|
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 uint32_t doTransaction(uint32_t transactionFlags);
|
||||||
virtual Point getPhysicalSize() const;
|
|
||||||
virtual void lockPageFlip(bool& recomputeVisibleRegions);
|
virtual void lockPageFlip(bool& recomputeVisibleRegions);
|
||||||
virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
|
virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
|
||||||
virtual void finishPageFlip();
|
virtual void finishPageFlip();
|
||||||
@@ -81,41 +76,30 @@ public:
|
|||||||
virtual sp<Surface> createSurface() const;
|
virtual sp<Surface> createSurface() const;
|
||||||
virtual status_t ditch();
|
virtual status_t ditch();
|
||||||
|
|
||||||
const LayerBitmap& getBuffer(int i) const { return mBuffers[i]; }
|
|
||||||
LayerBitmap& getBuffer(int i) { return mBuffers[i]; }
|
|
||||||
|
|
||||||
// only for debugging
|
// 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:
|
private:
|
||||||
inline const LayerBitmap&
|
inline sp<Buffer> getFrontBuffer() {
|
||||||
frontBuffer() const { return getBuffer(mFrontBufferIndex); }
|
return mBuffers[mFrontBufferIndex];
|
||||||
inline LayerBitmap&
|
}
|
||||||
frontBuffer() { return getBuffer(mFrontBufferIndex); }
|
|
||||||
inline const LayerBitmap&
|
|
||||||
backBuffer() const { return getBuffer(1-mFrontBufferIndex); }
|
|
||||||
inline LayerBitmap&
|
|
||||||
backBuffer() { return getBuffer(1-mFrontBufferIndex); }
|
|
||||||
|
|
||||||
void reloadTexture(const Region& dirty);
|
void reloadTexture(const Region& dirty);
|
||||||
|
|
||||||
status_t resize(int32_t index, uint32_t w, uint32_t h, const char* what);
|
sp<SurfaceBuffer> requestBuffer(int index, int usage);
|
||||||
Region post(uint32_t* oldState, bool& recomputeVisibleRegions);
|
|
||||||
sp<SurfaceBuffer> peekBuffer(int usage);
|
|
||||||
void destroy();
|
void destroy();
|
||||||
void scheduleBroadcast();
|
|
||||||
|
|
||||||
|
class SurfaceLayer : public LayerBaseClient::Surface {
|
||||||
class SurfaceLayer : public LayerBaseClient::Surface
|
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
SurfaceLayer(const sp<SurfaceFlinger>& flinger,
|
SurfaceLayer(const sp<SurfaceFlinger>& flinger,
|
||||||
SurfaceID id, const sp<Layer>& owner);
|
SurfaceID id, const sp<Layer>& owner);
|
||||||
~SurfaceLayer();
|
~SurfaceLayer();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual sp<SurfaceBuffer> getBuffer(int usage);
|
virtual sp<SurfaceBuffer> requestBuffer(int index, int usage);
|
||||||
|
|
||||||
sp<Layer> getOwner() const {
|
sp<Layer> getOwner() const {
|
||||||
return static_cast<Layer*>(Surface::getOwner().get());
|
return static_cast<Layer*>(Surface::getOwner().get());
|
||||||
}
|
}
|
||||||
@@ -125,13 +109,20 @@ private:
|
|||||||
sp<Surface> mSurface;
|
sp<Surface> mSurface;
|
||||||
|
|
||||||
bool mSecure;
|
bool mSecure;
|
||||||
LayerBitmap mBuffers[NUM_BUFFERS];
|
|
||||||
Texture mTextures[NUM_BUFFERS];
|
|
||||||
int32_t mFrontBufferIndex;
|
int32_t mFrontBufferIndex;
|
||||||
bool mNeedsBlending;
|
bool mNeedsBlending;
|
||||||
bool mResizeTransactionDone;
|
|
||||||
Region mPostedDirtyRegion;
|
Region mPostedDirtyRegion;
|
||||||
sp<FreezeLock> mFreezeLock;
|
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 "clz.h"
|
||||||
#include "LayerBase.h"
|
#include "LayerBase.h"
|
||||||
#include "LayerBlur.h"
|
|
||||||
#include "SurfaceFlinger.h"
|
#include "SurfaceFlinger.h"
|
||||||
#include "DisplayHardware/DisplayHardware.h"
|
#include "DisplayHardware/DisplayHardware.h"
|
||||||
|
|
||||||
@@ -127,9 +126,6 @@ uint32_t LayerBase::setTransactionFlags(uint32_t flags) {
|
|||||||
return android_atomic_or(flags, &mTransactionFlags);
|
return android_atomic_or(flags, &mTransactionFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LayerBase::setSizeChanged(uint32_t w, uint32_t h) {
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LayerBase::setPosition(int32_t x, int32_t y) {
|
bool LayerBase::setPosition(int32_t x, int32_t y) {
|
||||||
if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y)
|
if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y)
|
||||||
return false;
|
return false;
|
||||||
@@ -149,7 +145,6 @@ bool LayerBase::setLayer(uint32_t z) {
|
|||||||
bool LayerBase::setSize(uint32_t w, uint32_t h) {
|
bool LayerBase::setSize(uint32_t w, uint32_t h) {
|
||||||
if (mCurrentState.w == w && mCurrentState.h == h)
|
if (mCurrentState.w == w && mCurrentState.h == h)
|
||||||
return false;
|
return false;
|
||||||
setSizeChanged(w, h);
|
|
||||||
mCurrentState.w = w;
|
mCurrentState.w = w;
|
||||||
mCurrentState.h = h;
|
mCurrentState.h = h;
|
||||||
requestTransaction();
|
requestTransaction();
|
||||||
@@ -219,21 +214,14 @@ uint32_t LayerBase::doTransaction(uint32_t flags)
|
|||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
Point LayerBase::getPhysicalSize() const
|
|
||||||
{
|
|
||||||
const Layer::State& front(drawingState());
|
|
||||||
return Point(front.w, front.h);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LayerBase::validateVisibility(const Transform& planeTransform)
|
void LayerBase::validateVisibility(const Transform& planeTransform)
|
||||||
{
|
{
|
||||||
const Layer::State& s(drawingState());
|
const Layer::State& s(drawingState());
|
||||||
const Transform tr(planeTransform * s.transform);
|
const Transform tr(planeTransform * s.transform);
|
||||||
const bool transformed = tr.transformed();
|
const bool transformed = tr.transformed();
|
||||||
|
|
||||||
const Point size(getPhysicalSize());
|
uint32_t w = s.w;
|
||||||
uint32_t w = size.x;
|
uint32_t h = s.h;
|
||||||
uint32_t h = size.y;
|
|
||||||
tr.transform(mVertices[0], 0, 0);
|
tr.transform(mVertices[0], 0, 0);
|
||||||
tr.transform(mVertices[1], 0, h);
|
tr.transform(mVertices[1], 0, h);
|
||||||
tr.transform(mVertices[2], w, h);
|
tr.transform(mVertices[2], w, h);
|
||||||
@@ -655,9 +643,7 @@ int32_t LayerBaseClient::sIdentity = 0;
|
|||||||
LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
|
LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
|
||||||
const sp<Client>& client, int32_t i)
|
const sp<Client>& client, int32_t i)
|
||||||
: LayerBase(flinger, display), client(client),
|
: 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());
|
sp<Client> client(this->client.promote());
|
||||||
if (client != 0) {
|
if (client != 0) {
|
||||||
client->bindLayer(this, mIndex);
|
client->bindLayer(this, mIndex);
|
||||||
// Initialize this layer's control block
|
// Initialize this layer's identity
|
||||||
memset(this->lcblk, 0, sizeof(layer_cblk_t));
|
client->ctrlblk->setIdentity(mIndex, mIdentity);
|
||||||
this->lcblk->identity = mIdentity;
|
|
||||||
Region::writeEmpty(&(this->lcblk->region[0]), sizeof(flat_region_t));
|
|
||||||
Region::writeEmpty(&(this->lcblk->region[1]), sizeof(flat_region_t));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -759,7 +742,7 @@ status_t LayerBaseClient::Surface::onTransact(
|
|||||||
return BnSurface::onTransact(code, data, reply, flags);
|
return BnSurface::onTransact(code, data, reply, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
sp<SurfaceBuffer> LayerBaseClient::Surface::getBuffer(int)
|
sp<SurfaceBuffer> LayerBaseClient::Surface::requestBuffer(int index, int usage)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include <EGL/egl.h>
|
#include <EGL/egl.h>
|
||||||
#include <EGL/eglext.h>
|
#include <EGL/eglext.h>
|
||||||
|
|
||||||
|
#include <private/ui/SharedBufferStack.h>
|
||||||
#include <private/ui/LayerState.h>
|
#include <private/ui/LayerState.h>
|
||||||
|
|
||||||
#include <utils/RefBase.h>
|
#include <utils/RefBase.h>
|
||||||
@@ -136,11 +137,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual void initStates(uint32_t w, uint32_t h, uint32_t flags);
|
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
|
* doTransaction - process the transaction. This is a good place to figure
|
||||||
* out which attributes of the surface have changed.
|
* out which attributes of the surface have changed.
|
||||||
@@ -160,13 +156,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual void setCoveredRegion(const Region& coveredRegion);
|
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
|
* validateVisibility - cache a bunch of things
|
||||||
*/
|
*/
|
||||||
@@ -308,8 +297,8 @@ public:
|
|||||||
virtual ~LayerBaseClient();
|
virtual ~LayerBaseClient();
|
||||||
virtual void onFirstRef();
|
virtual void onFirstRef();
|
||||||
|
|
||||||
wp<Client> client;
|
wp<Client> client;
|
||||||
layer_cblk_t* const lcblk;
|
// SharedBufferServer* lcblk;
|
||||||
|
|
||||||
inline uint32_t getIdentity() const { return mIdentity; }
|
inline uint32_t getIdentity() const { return mIdentity; }
|
||||||
inline int32_t clientIndex() const { return mIndex; }
|
inline int32_t clientIndex() const { return mIndex; }
|
||||||
@@ -336,7 +325,7 @@ public:
|
|||||||
sp<LayerBaseClient> getOwner() const;
|
sp<LayerBaseClient> getOwner() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual sp<SurfaceBuffer> getBuffer(int usage);
|
virtual sp<SurfaceBuffer> requestBuffer(int index, int usage);
|
||||||
virtual status_t registerBuffers(const ISurface::BufferHeap& buffers);
|
virtual status_t registerBuffers(const ISurface::BufferHeap& buffers);
|
||||||
virtual void postBuffer(ssize_t offset);
|
virtual void postBuffer(ssize_t offset);
|
||||||
virtual void unregisterBuffers();
|
virtual void unregisterBuffers();
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
#include <hardware/copybit.h>
|
#include <hardware/copybit.h>
|
||||||
|
|
||||||
|
#include "Buffer.h"
|
||||||
#include "BufferAllocator.h"
|
#include "BufferAllocator.h"
|
||||||
#include "LayerBuffer.h"
|
#include "LayerBuffer.h"
|
||||||
#include "SurfaceFlinger.h"
|
#include "SurfaceFlinger.h"
|
||||||
@@ -58,7 +59,7 @@ LayerBuffer::~LayerBuffer()
|
|||||||
void LayerBuffer::onFirstRef()
|
void LayerBuffer::onFirstRef()
|
||||||
{
|
{
|
||||||
LayerBaseClient::onFirstRef();
|
LayerBaseClient::onFirstRef();
|
||||||
mSurface = new SurfaceBuffer(mFlinger, clientIndex(),
|
mSurface = new SurfaceLayerBuffer(mFlinger, clientIndex(),
|
||||||
const_cast<LayerBuffer *>(this));
|
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)
|
SurfaceID id, const sp<LayerBuffer>& owner)
|
||||||
: LayerBaseClient::Surface(flinger, id, owner->getIdentity(), owner)
|
: LayerBaseClient::Surface(flinger, id, owner->getIdentity(), owner)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
LayerBuffer::SurfaceBuffer::~SurfaceBuffer()
|
LayerBuffer::SurfaceLayerBuffer::~SurfaceLayerBuffer()
|
||||||
{
|
{
|
||||||
unregisterBuffers();
|
unregisterBuffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t LayerBuffer::SurfaceBuffer::registerBuffers(
|
status_t LayerBuffer::SurfaceLayerBuffer::registerBuffers(
|
||||||
const ISurface::BufferHeap& buffers)
|
const ISurface::BufferHeap& buffers)
|
||||||
{
|
{
|
||||||
sp<LayerBuffer> owner(getOwner());
|
sp<LayerBuffer> owner(getOwner());
|
||||||
@@ -204,21 +205,21 @@ status_t LayerBuffer::SurfaceBuffer::registerBuffers(
|
|||||||
return NO_INIT;
|
return NO_INIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LayerBuffer::SurfaceBuffer::postBuffer(ssize_t offset)
|
void LayerBuffer::SurfaceLayerBuffer::postBuffer(ssize_t offset)
|
||||||
{
|
{
|
||||||
sp<LayerBuffer> owner(getOwner());
|
sp<LayerBuffer> owner(getOwner());
|
||||||
if (owner != 0)
|
if (owner != 0)
|
||||||
owner->postBuffer(offset);
|
owner->postBuffer(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LayerBuffer::SurfaceBuffer::unregisterBuffers()
|
void LayerBuffer::SurfaceLayerBuffer::unregisterBuffers()
|
||||||
{
|
{
|
||||||
sp<LayerBuffer> owner(getOwner());
|
sp<LayerBuffer> owner(getOwner());
|
||||||
if (owner != 0)
|
if (owner != 0)
|
||||||
owner->unregisterBuffers();
|
owner->unregisterBuffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
sp<OverlayRef> LayerBuffer::SurfaceBuffer::createOverlay(
|
sp<OverlayRef> LayerBuffer::SurfaceLayerBuffer::createOverlay(
|
||||||
uint32_t w, uint32_t h, int32_t format) {
|
uint32_t w, uint32_t h, int32_t format) {
|
||||||
sp<OverlayRef> result;
|
sp<OverlayRef> result;
|
||||||
sp<LayerBuffer> owner(getOwner());
|
sp<LayerBuffer> owner(getOwner());
|
||||||
@@ -462,8 +463,8 @@ void LayerBuffer::BufferSource::onDraw(const Region& clip) const
|
|||||||
const int tmp_h = floorf(src_height * yscale);
|
const int tmp_h = floorf(src_height * yscale);
|
||||||
|
|
||||||
if (mTempBitmap==0 ||
|
if (mTempBitmap==0 ||
|
||||||
mTempBitmap->getWidth() < tmp_w ||
|
mTempBitmap->getWidth() < size_t(tmp_w) ||
|
||||||
mTempBitmap->getHeight() < tmp_h) {
|
mTempBitmap->getHeight() < size_t(tmp_h)) {
|
||||||
mTempBitmap.clear();
|
mTempBitmap.clear();
|
||||||
mTempBitmap = new android::Buffer(
|
mTempBitmap = new android::Buffer(
|
||||||
tmp_w, tmp_h, src.img.format,
|
tmp_w, tmp_h, src.img.format,
|
||||||
|
|||||||
@@ -24,7 +24,6 @@
|
|||||||
#include <private/ui/LayerState.h>
|
#include <private/ui/LayerState.h>
|
||||||
|
|
||||||
#include "LayerBase.h"
|
#include "LayerBase.h"
|
||||||
#include "LayerBitmap.h"
|
|
||||||
|
|
||||||
struct copybit_device_t;
|
struct copybit_device_t;
|
||||||
|
|
||||||
@@ -32,9 +31,12 @@ namespace android {
|
|||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class Buffer;
|
||||||
class Region;
|
class Region;
|
||||||
class OverlayRef;
|
class OverlayRef;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
class LayerBuffer : public LayerBaseClient
|
class LayerBuffer : public LayerBaseClient
|
||||||
{
|
{
|
||||||
class Source : public LightRefBase<Source> {
|
class Source : public LightRefBase<Source> {
|
||||||
@@ -179,12 +181,12 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class SurfaceBuffer : public LayerBaseClient::Surface
|
class SurfaceLayerBuffer : public LayerBaseClient::Surface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SurfaceBuffer(const sp<SurfaceFlinger>& flinger,
|
SurfaceLayerBuffer(const sp<SurfaceFlinger>& flinger,
|
||||||
SurfaceID id, const sp<LayerBuffer>& owner);
|
SurfaceID id, const sp<LayerBuffer>& owner);
|
||||||
virtual ~SurfaceBuffer();
|
virtual ~SurfaceLayerBuffer();
|
||||||
|
|
||||||
virtual status_t registerBuffers(const ISurface::BufferHeap& buffers);
|
virtual status_t registerBuffers(const ISurface::BufferHeap& buffers);
|
||||||
virtual void postBuffer(ssize_t offset);
|
virtual void postBuffer(ssize_t offset);
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include <utils/Errors.h>
|
#include <utils/Errors.h>
|
||||||
#include <utils/Log.h>
|
#include <utils/Log.h>
|
||||||
|
|
||||||
|
#include "Buffer.h"
|
||||||
#include "BufferAllocator.h"
|
#include "BufferAllocator.h"
|
||||||
#include "LayerDim.h"
|
#include "LayerDim.h"
|
||||||
#include "SurfaceFlinger.h"
|
#include "SurfaceFlinger.h"
|
||||||
|
|||||||
@@ -24,12 +24,11 @@
|
|||||||
#include <EGL/eglext.h>
|
#include <EGL/eglext.h>
|
||||||
|
|
||||||
#include "LayerBase.h"
|
#include "LayerBase.h"
|
||||||
#include "LayerBitmap.h"
|
|
||||||
|
|
||||||
namespace android {
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
|
||||||
class LayerDim : public LayerBaseClient
|
class LayerDim : public LayerBaseClient
|
||||||
{
|
{
|
||||||
static bool sUseTexture;
|
static bool sUseTexture;
|
||||||
|
|||||||
@@ -44,12 +44,12 @@
|
|||||||
#include <GLES/gl.h>
|
#include <GLES/gl.h>
|
||||||
|
|
||||||
#include "clz.h"
|
#include "clz.h"
|
||||||
|
#include "Buffer.h"
|
||||||
#include "BufferAllocator.h"
|
#include "BufferAllocator.h"
|
||||||
#include "Layer.h"
|
#include "Layer.h"
|
||||||
#include "LayerBlur.h"
|
#include "LayerBlur.h"
|
||||||
#include "LayerBuffer.h"
|
#include "LayerBuffer.h"
|
||||||
#include "LayerDim.h"
|
#include "LayerDim.h"
|
||||||
#include "LayerBitmap.h"
|
|
||||||
#include "SurfaceFlinger.h"
|
#include "SurfaceFlinger.h"
|
||||||
|
|
||||||
#include "DisplayHardware/DisplayHardware.h"
|
#include "DisplayHardware/DisplayHardware.h"
|
||||||
@@ -173,12 +173,12 @@ SurfaceFlinger::SurfaceFlinger()
|
|||||||
: BnSurfaceComposer(), Thread(false),
|
: BnSurfaceComposer(), Thread(false),
|
||||||
mTransactionFlags(0),
|
mTransactionFlags(0),
|
||||||
mTransactionCount(0),
|
mTransactionCount(0),
|
||||||
|
mResizeTransationPending(false),
|
||||||
mLayersRemoved(false),
|
mLayersRemoved(false),
|
||||||
mBootTime(systemTime()),
|
mBootTime(systemTime()),
|
||||||
mHardwareTest("android.permission.HARDWARE_TEST"),
|
mHardwareTest("android.permission.HARDWARE_TEST"),
|
||||||
mAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"),
|
mAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"),
|
||||||
mDump("android.permission.DUMP"),
|
mDump("android.permission.DUMP"),
|
||||||
mLastScheduledBroadcast(NULL),
|
|
||||||
mVisibleRegionsDirty(false),
|
mVisibleRegionsDirty(false),
|
||||||
mDeferReleaseConsole(false),
|
mDeferReleaseConsole(false),
|
||||||
mFreezeDisplay(false),
|
mFreezeDisplay(false),
|
||||||
@@ -497,13 +497,11 @@ bool SurfaceFlinger::threadLoop()
|
|||||||
|
|
||||||
// release the clients before we flip ('cause flip might block)
|
// release the clients before we flip ('cause flip might block)
|
||||||
unlockClients();
|
unlockClients();
|
||||||
executeScheduledBroadcasts();
|
|
||||||
|
|
||||||
postFramebuffer();
|
postFramebuffer();
|
||||||
} else {
|
} else {
|
||||||
// pretend we did the post
|
// pretend we did the post
|
||||||
unlockClients();
|
unlockClients();
|
||||||
executeScheduledBroadcasts();
|
|
||||||
usleep(16667); // 60 fps period
|
usleep(16667); // 60 fps period
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -773,7 +771,8 @@ void SurfaceFlinger::computeVisibleRegions(
|
|||||||
void SurfaceFlinger::commitTransaction()
|
void SurfaceFlinger::commitTransaction()
|
||||||
{
|
{
|
||||||
mDrawingState = mCurrentState;
|
mDrawingState = mCurrentState;
|
||||||
mTransactionCV.signal();
|
mResizeTransationPending = false;
|
||||||
|
mTransactionCV.broadcast();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SurfaceFlinger::handlePageFlip()
|
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()
|
void SurfaceFlinger::debugFlashRegions()
|
||||||
{
|
{
|
||||||
const DisplayHardware& hw(graphicPlane(0).displayHardware());
|
const DisplayHardware& hw(graphicPlane(0).displayHardware());
|
||||||
@@ -1129,18 +1097,10 @@ void SurfaceFlinger::free_resources_l()
|
|||||||
mLayersRemoved = false;
|
mLayersRemoved = false;
|
||||||
|
|
||||||
// free resources associated with disconnected clients
|
// free resources associated with disconnected clients
|
||||||
SortedVector< wp<Client> >& scheduledBroadcasts(mScheduledBroadcasts);
|
|
||||||
Vector< sp<Client> >& disconnectedClients(mDisconnectedClients);
|
Vector< sp<Client> >& disconnectedClients(mDisconnectedClients);
|
||||||
const size_t count = disconnectedClients.size();
|
const size_t count = disconnectedClients.size();
|
||||||
for (size_t i=0 ; i<count ; i++) {
|
for (size_t i=0 ; i<count ; i++) {
|
||||||
sp<Client> client = disconnectedClients[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);
|
mTokens.release(client->cid);
|
||||||
}
|
}
|
||||||
disconnectedClients.clear();
|
disconnectedClients.clear();
|
||||||
@@ -1173,6 +1133,13 @@ void SurfaceFlinger::closeGlobalTransaction()
|
|||||||
{
|
{
|
||||||
if (android_atomic_dec(&mTransactionCount) == 1) {
|
if (android_atomic_dec(&mTransactionCount) == 1) {
|
||||||
signalEvent();
|
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 (what & eSizeChanged) {
|
||||||
if (layer->setSize(s.w, s.h))
|
if (layer->setSize(s.w, s.h)) {
|
||||||
flags |= eTraversalNeeded;
|
flags |= eTraversalNeeded;
|
||||||
|
mResizeTransationPending = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (what & eAlphaChanged) {
|
if (what & eAlphaChanged) {
|
||||||
if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f)))
|
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",
|
"id=0x%08x, client=0x%08x, identity=%u\n",
|
||||||
lbc->clientIndex(), client.get() ? client->cid : 0,
|
lbc->clientIndex(), client.get() ? client->cid : 0,
|
||||||
lbc->getIdentity());
|
lbc->getIdentity());
|
||||||
|
|
||||||
|
result.append(buffer);
|
||||||
|
buffer[0] = 0;
|
||||||
}
|
}
|
||||||
result.append(buffer);
|
|
||||||
buffer[0] = 0;
|
|
||||||
/*** Layer ***/
|
/*** Layer ***/
|
||||||
sp<Layer> l = LayerBase::dynamicCast< Layer* >(layer.get());
|
sp<Layer> l = LayerBase::dynamicCast< Layer* >(layer.get());
|
||||||
if (l != 0) {
|
if (l != 0) {
|
||||||
const LayerBitmap& buf0(l->getBuffer(0));
|
result.append( l->lcblk->dump(" ") );
|
||||||
const LayerBitmap& buf1(l->getBuffer(1));
|
sp<const Buffer> buf0(l->getBuffer(0));
|
||||||
|
sp<const Buffer> buf1(l->getBuffer(1));
|
||||||
snprintf(buffer, SIZE,
|
snprintf(buffer, SIZE,
|
||||||
" "
|
" "
|
||||||
"format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u],"
|
"format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u],"
|
||||||
" freezeLock=%p, swapState=0x%08x\n",
|
" freezeLock=%p\n",
|
||||||
l->pixelFormat(),
|
l->pixelFormat(),
|
||||||
buf0.getWidth(), buf0.getHeight(),
|
buf0->getWidth(), buf0->getHeight(), buf0->getStride(),
|
||||||
buf0.getBuffer()->getStride(),
|
buf1->getWidth(), buf1->getHeight(), buf1->getStride(),
|
||||||
buf1.getWidth(), buf1.getHeight(),
|
l->getFreezeLock().get());
|
||||||
buf1.getBuffer()->getStride(),
|
result.append(buffer);
|
||||||
l->getFreezeLock().get(),
|
buffer[0] = 0;
|
||||||
l->lcblk->swapState);
|
|
||||||
}
|
}
|
||||||
result.append(buffer);
|
|
||||||
buffer[0] = 0;
|
|
||||||
s.transparentRegion.dump(result, "transparentRegion");
|
s.transparentRegion.dump(result, "transparentRegion");
|
||||||
layer->transparentRegionScreen.dump(result, "transparentRegionScreen");
|
layer->transparentRegionScreen.dump(result, "transparentRegionScreen");
|
||||||
layer->visibleRegionScreen.dump(result, "visibleRegionScreen");
|
layer->visibleRegionScreen.dump(result, "visibleRegionScreen");
|
||||||
@@ -1657,8 +1625,12 @@ status_t SurfaceFlinger::onTransact(
|
|||||||
const DisplayHardware& hw(graphicPlane(0).displayHardware());
|
const DisplayHardware& hw(graphicPlane(0).displayHardware());
|
||||||
mDirtyRegion.set(hw.bounds()); // careful that's not thread-safe
|
mDirtyRegion.set(hw.bounds()); // careful that's not thread-safe
|
||||||
signalEvent();
|
signalEvent();
|
||||||
|
return NO_ERROR;
|
||||||
|
}
|
||||||
|
case 1005:{ // force transaction
|
||||||
|
setTransactionFlags(eTransactionNeeded|eTraversalNeeded);
|
||||||
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
return NO_ERROR;
|
|
||||||
case 1007: // set mFreezeCount
|
case 1007: // set mFreezeCount
|
||||||
mFreezeCount = data.readInt32();
|
mFreezeCount = data.readInt32();
|
||||||
return NO_ERROR;
|
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)
|
: ctrlblk(0), cid(clientID), mPid(0), mBitmap(0), mFlinger(flinger)
|
||||||
{
|
{
|
||||||
const int pgsize = getpagesize();
|
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,
|
mCblkHeap = new MemoryHeapBase(cblksize, 0,
|
||||||
"SurfaceFlinger Client control-block");
|
"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.
|
if (ctrlblk) { // construct the shared structure in-place.
|
||||||
new(ctrlblk) per_client_cblk_t;
|
new(ctrlblk) SharedClient;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Client::~Client() {
|
Client::~Client() {
|
||||||
if (ctrlblk) {
|
if (ctrlblk) {
|
||||||
const int pgsize = getpagesize();
|
ctrlblk->~SharedClient(); // destroy our shared-structure.
|
||||||
ctrlblk->~per_client_cblk_t(); // destroy our shared-structure.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
#include <ui/ISurfaceComposer.h>
|
#include <ui/ISurfaceComposer.h>
|
||||||
#include <ui/ISurfaceFlingerClient.h>
|
#include <ui/ISurfaceFlingerClient.h>
|
||||||
|
|
||||||
#include <private/ui/SharedState.h>
|
#include <private/ui/SharedBufferStack.h>
|
||||||
#include <private/ui/LayerState.h>
|
#include <private/ui/LayerState.h>
|
||||||
|
|
||||||
#include "Barrier.h"
|
#include "Barrier.h"
|
||||||
@@ -87,7 +87,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// pointer to this client's control block
|
// pointer to this client's control block
|
||||||
per_client_cblk_t* ctrlblk;
|
SharedClient* ctrlblk;
|
||||||
ClientID cid;
|
ClientID cid;
|
||||||
|
|
||||||
|
|
||||||
@@ -268,8 +268,6 @@ private:
|
|||||||
bool lockPageFlip(const LayerVector& currentLayers);
|
bool lockPageFlip(const LayerVector& currentLayers);
|
||||||
void unlockPageFlip(const LayerVector& currentLayers);
|
void unlockPageFlip(const LayerVector& currentLayers);
|
||||||
void handleRepaint();
|
void handleRepaint();
|
||||||
void scheduleBroadcast(const sp<Client>& client);
|
|
||||||
void executeScheduledBroadcasts();
|
|
||||||
void postFramebuffer();
|
void postFramebuffer();
|
||||||
void composeSurfaces(const Region& dirty);
|
void composeSurfaces(const Region& dirty);
|
||||||
void unlockClients();
|
void unlockClients();
|
||||||
@@ -313,6 +311,7 @@ private:
|
|||||||
volatile int32_t mTransactionFlags;
|
volatile int32_t mTransactionFlags;
|
||||||
volatile int32_t mTransactionCount;
|
volatile int32_t mTransactionCount;
|
||||||
Condition mTransactionCV;
|
Condition mTransactionCV;
|
||||||
|
bool mResizeTransationPending;
|
||||||
|
|
||||||
// protected by mStateLock (but we could use another lock)
|
// protected by mStateLock (but we could use another lock)
|
||||||
Tokenizer mTokens;
|
Tokenizer mTokens;
|
||||||
@@ -337,8 +336,6 @@ private:
|
|||||||
Region mDirtyRegionRemovedLayer;
|
Region mDirtyRegionRemovedLayer;
|
||||||
Region mInvalidRegion;
|
Region mInvalidRegion;
|
||||||
Region mWormholeRegion;
|
Region mWormholeRegion;
|
||||||
wp<Client> mLastScheduledBroadcast;
|
|
||||||
SortedVector< wp<Client> > mScheduledBroadcasts;
|
|
||||||
bool mVisibleRegionsDirty;
|
bool mVisibleRegionsDirty;
|
||||||
bool mDeferReleaseConsole;
|
bool mDeferReleaseConsole;
|
||||||
bool mFreezeDisplay;
|
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 \
|
PixelFormat.cpp \
|
||||||
Rect.cpp \
|
Rect.cpp \
|
||||||
Region.cpp \
|
Region.cpp \
|
||||||
|
SharedBufferStack.cpp \
|
||||||
Surface.cpp \
|
Surface.cpp \
|
||||||
|
SurfaceBuffer.cpp \
|
||||||
SurfaceComposerClient.cpp \
|
SurfaceComposerClient.cpp \
|
||||||
SurfaceFlingerSynchro.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;
|
Parcel data, reply;
|
||||||
data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
|
data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
|
||||||
|
data.writeInt32(bufferIdx);
|
||||||
data.writeInt32(usage);
|
data.writeInt32(usage);
|
||||||
remote()->transact(GET_BUFFER, data, &reply);
|
remote()->transact(REQUEST_BUFFER, data, &reply);
|
||||||
sp<SurfaceBuffer> buffer = new SurfaceBuffer(reply);
|
sp<SurfaceBuffer> buffer = new SurfaceBuffer(reply);
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
@@ -134,10 +135,11 @@ status_t BnSurface::onTransact(
|
|||||||
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
|
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
|
||||||
{
|
{
|
||||||
switch(code) {
|
switch(code) {
|
||||||
case GET_BUFFER: {
|
case REQUEST_BUFFER: {
|
||||||
CHECK_INTERFACE(ISurface, data, reply);
|
CHECK_INTERFACE(ISurface, data, reply);
|
||||||
|
int bufferIdx = data.readInt32();
|
||||||
int usage = data.readInt32();
|
int usage = data.readInt32();
|
||||||
sp<SurfaceBuffer> buffer(getBuffer(usage));
|
sp<SurfaceBuffer> buffer(requestBuffer(bufferIdx, usage));
|
||||||
return SurfaceBuffer::writeToParcel(reply, buffer.get());
|
return SurfaceBuffer::writeToParcel(reply, buffer.get());
|
||||||
}
|
}
|
||||||
case REGISTER_BUFFERS: {
|
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/Errors.h>
|
||||||
#include <utils/threads.h>
|
#include <utils/threads.h>
|
||||||
|
#include <utils/CallStack.h>
|
||||||
#include <binder/IPCThreadState.h>
|
#include <binder/IPCThreadState.h>
|
||||||
#include <binder/IMemory.h>
|
#include <binder/IMemory.h>
|
||||||
#include <utils/Log.h>
|
#include <utils/Log.h>
|
||||||
@@ -38,102 +39,12 @@
|
|||||||
|
|
||||||
#include <pixelflinger/pixelflinger.h>
|
#include <pixelflinger/pixelflinger.h>
|
||||||
|
|
||||||
#include <private/ui/SharedState.h>
|
#include <private/ui/SharedBufferStack.h>
|
||||||
#include <private/ui/LayerState.h>
|
#include <private/ui/LayerState.h>
|
||||||
#include <private/ui/SurfaceBuffer.h>
|
#include <private/ui/SurfaceBuffer.h>
|
||||||
|
|
||||||
namespace android {
|
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(
|
static status_t copyBlt(
|
||||||
@@ -324,7 +235,7 @@ status_t SurfaceControl::setFreezeTint(uint32_t tint) {
|
|||||||
return client->setFreezeTint(mToken, 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) {
|
if (mToken<0 || mClient==0) {
|
||||||
LOGE("invalid token (%d, identity=%u) or client (%p)",
|
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));
|
mToken, mIdentity, err, strerror(-err));
|
||||||
return 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",
|
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_INIT;
|
||||||
}
|
}
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
@@ -398,14 +310,17 @@ Surface::Surface(const sp<SurfaceControl>& surface)
|
|||||||
: mClient(surface->mClient), mSurface(surface->mSurface),
|
: mClient(surface->mClient), mSurface(surface->mSurface),
|
||||||
mToken(surface->mToken), mIdentity(surface->mIdentity),
|
mToken(surface->mToken), mIdentity(surface->mIdentity),
|
||||||
mFormat(surface->mFormat), mFlags(surface->mFlags),
|
mFormat(surface->mFormat), mFlags(surface->mFlags),
|
||||||
mBufferMapper(BufferMapper::get()),
|
mBufferMapper(BufferMapper::get()), mSharedBufferClient(NULL),
|
||||||
mWidth(surface->mWidth), mHeight(surface->mHeight)
|
mWidth(surface->mWidth), mHeight(surface->mHeight)
|
||||||
{
|
{
|
||||||
|
mSharedBufferClient = new SharedBufferClient(
|
||||||
|
mClient->mControl, mToken, 2);
|
||||||
|
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
Surface::Surface(const Parcel& parcel)
|
Surface::Surface(const Parcel& parcel)
|
||||||
: mBufferMapper(BufferMapper::get())
|
: mBufferMapper(BufferMapper::get()), mSharedBufferClient(NULL)
|
||||||
{
|
{
|
||||||
sp<IBinder> clientBinder = parcel.readStrongBinder();
|
sp<IBinder> clientBinder = parcel.readStrongBinder();
|
||||||
mSurface = interface_cast<ISurface>(parcel.readStrongBinder());
|
mSurface = interface_cast<ISurface>(parcel.readStrongBinder());
|
||||||
@@ -416,9 +331,14 @@ Surface::Surface(const Parcel& parcel)
|
|||||||
mFormat = parcel.readInt32();
|
mFormat = parcel.readInt32();
|
||||||
mFlags = 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);
|
mClient = SurfaceComposerClient::clientForConnection(clientBinder);
|
||||||
|
|
||||||
|
mSharedBufferClient = new SharedBufferClient(
|
||||||
|
mClient->mControl, mToken, 2);
|
||||||
|
}
|
||||||
|
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -442,6 +362,7 @@ void Surface::init()
|
|||||||
// be default we request a hardware surface
|
// be default we request a hardware surface
|
||||||
mUsage = GRALLOC_USAGE_HW_RENDER;
|
mUsage = GRALLOC_USAGE_HW_RENDER;
|
||||||
mUsageChanged = true;
|
mUsageChanged = true;
|
||||||
|
mNeedFullUpdate = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Surface::~Surface()
|
Surface::~Surface()
|
||||||
@@ -458,6 +379,7 @@ Surface::~Surface()
|
|||||||
// happen without delay, since these resources are quite heavy.
|
// happen without delay, since these resources are quite heavy.
|
||||||
mClient.clear();
|
mClient.clear();
|
||||||
mSurface.clear();
|
mSurface.clear();
|
||||||
|
delete mSharedBufferClient;
|
||||||
IPCThreadState::self()->flushCommands();
|
IPCThreadState::self()->flushCommands();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -473,7 +395,7 @@ bool Surface::isValid() {
|
|||||||
return mToken>=0 && mClient!=0;
|
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());
|
sp<SurfaceComposerClient> client(getClient());
|
||||||
if (mToken<0 || mClient==0) {
|
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));
|
mToken, mIdentity, err, strerror(-err));
|
||||||
return 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",
|
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_INIT;
|
||||||
}
|
}
|
||||||
return NO_ERROR;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Surface::dequeueBuffer(android_native_window_t* window,
|
int Surface::dequeueBuffer(android_native_window_t* window,
|
||||||
android_native_buffer_t** buffer)
|
android_native_buffer_t** buffer) {
|
||||||
{
|
|
||||||
Surface* self = getSelf(window);
|
Surface* self = getSelf(window);
|
||||||
return self->dequeueBuffer(buffer);
|
return self->dequeueBuffer(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Surface::lockBuffer(android_native_window_t* window,
|
int Surface::lockBuffer(android_native_window_t* window,
|
||||||
android_native_buffer_t* buffer)
|
android_native_buffer_t* buffer) {
|
||||||
{
|
|
||||||
Surface* self = getSelf(window);
|
Surface* self = getSelf(window);
|
||||||
return self->lockBuffer(buffer);
|
return self->lockBuffer(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Surface::queueBuffer(android_native_window_t* window,
|
int Surface::queueBuffer(android_native_window_t* window,
|
||||||
android_native_buffer_t* buffer)
|
android_native_buffer_t* buffer) {
|
||||||
{
|
|
||||||
Surface* self = getSelf(window);
|
Surface* self = getSelf(window);
|
||||||
return self->queueBuffer(buffer);
|
return self->queueBuffer(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Surface::query(android_native_window_t* window,
|
int Surface::query(android_native_window_t* window,
|
||||||
int what, int* value)
|
int what, int* value) {
|
||||||
{
|
|
||||||
Surface* self = getSelf(window);
|
Surface* self = getSelf(window);
|
||||||
return self->query(what, value);
|
return self->query(what, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Surface::perform(android_native_window_t* window,
|
int Surface::perform(android_native_window_t* window,
|
||||||
int operation, ...)
|
int operation, ...) {
|
||||||
{
|
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, operation);
|
va_start(args, operation);
|
||||||
Surface* self = getSelf(window);
|
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;
|
android_native_buffer_t* out;
|
||||||
status_t err = dequeueBuffer(&out);
|
status_t err = dequeueBuffer(&out);
|
||||||
if (err == NO_ERROR) {
|
if (err == NO_ERROR) {
|
||||||
@@ -567,70 +483,49 @@ status_t Surface::dequeueBuffer(sp<SurfaceBuffer>* buffer)
|
|||||||
return err;
|
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)
|
int Surface::dequeueBuffer(android_native_buffer_t** buffer)
|
||||||
{
|
{
|
||||||
// FIXME: dequeueBuffer() needs proper implementation
|
|
||||||
|
|
||||||
Mutex::Autolock _l(mSurfaceLock);
|
|
||||||
|
|
||||||
sp<SurfaceComposerClient> client(getClient());
|
sp<SurfaceComposerClient> client(getClient());
|
||||||
per_client_cblk_t* const cblk = client->mControl;
|
status_t err = validate(client->mControl);
|
||||||
status_t err = validate(cblk);
|
|
||||||
if (err != NO_ERROR)
|
if (err != NO_ERROR)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
SurfaceID index(mToken);
|
ssize_t bufIdx = mSharedBufferClient->dequeue();
|
||||||
|
if (bufIdx < 0) {
|
||||||
int32_t backIdx = cblk->lock_layer(size_t(index),
|
LOGE("error dequeuing a buffer (%s)", strerror(bufIdx));
|
||||||
per_client_cblk_t::BLOCKING);
|
return bufIdx;
|
||||||
|
|
||||||
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...");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((back->flags & surface_info_t::eNeedNewBuffer) ||mUsageChanged ||
|
// FIXME: in case of failure below, we need to undo the dequeue
|
||||||
backBuffer==0)
|
|
||||||
{
|
uint32_t usage;
|
||||||
mUsageChanged = false;
|
const bool usageChanged = getUsage(&usage);
|
||||||
err = getBufferLocked(backIdx, mUsage);
|
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) {
|
if (err == NO_ERROR) {
|
||||||
// reset the width/height with the what we get from the buffer
|
// reset the width/height with the what we get from the buffer
|
||||||
const sp<SurfaceBuffer>& backBuffer(mBuffers[backIdx]);
|
|
||||||
mWidth = uint32_t(backBuffer->width);
|
mWidth = uint32_t(backBuffer->width);
|
||||||
mHeight = uint32_t(backBuffer->height);
|
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 (err == NO_ERROR) {
|
||||||
if (backBuffer != 0) {
|
mDirtyRegion.set(backBuffer->width, backBuffer->height);
|
||||||
mDirtyRegion.set(backBuffer->width, backBuffer->height);
|
*buffer = backBuffer.get();
|
||||||
*buffer = backBuffer.get();
|
} else {
|
||||||
} else {
|
mSharedBufferClient->undoDequeue(bufIdx);
|
||||||
err = NO_MEMORY;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
@@ -638,25 +533,21 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer)
|
|||||||
|
|
||||||
int Surface::lockBuffer(android_native_buffer_t* buffer)
|
int Surface::lockBuffer(android_native_buffer_t* buffer)
|
||||||
{
|
{
|
||||||
Mutex::Autolock _l(mSurfaceLock);
|
|
||||||
|
|
||||||
sp<SurfaceComposerClient> client(getClient());
|
sp<SurfaceComposerClient> client(getClient());
|
||||||
per_client_cblk_t* const cblk = client->mControl;
|
status_t err = validate(client->mControl);
|
||||||
status_t err = validate(cblk);
|
|
||||||
if (err != NO_ERROR)
|
if (err != NO_ERROR)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
// FIXME: lockBuffer() needs proper implementation
|
int32_t bufIdx = SurfaceBuffer::getSelf(buffer)->getIndex();
|
||||||
return 0;
|
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)
|
int Surface::queueBuffer(android_native_buffer_t* buffer)
|
||||||
{
|
{
|
||||||
Mutex::Autolock _l(mSurfaceLock);
|
|
||||||
|
|
||||||
sp<SurfaceComposerClient> client(getClient());
|
sp<SurfaceComposerClient> client(getClient());
|
||||||
per_client_cblk_t* const cblk = client->mControl;
|
status_t err = validate(client->mControl);
|
||||||
status_t err = validate(cblk);
|
|
||||||
if (err != NO_ERROR)
|
if (err != NO_ERROR)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@@ -664,30 +555,30 @@ int Surface::queueBuffer(android_native_buffer_t* buffer)
|
|||||||
mDirtyRegion.set(mSwapRectangle);
|
mDirtyRegion.set(mSwapRectangle);
|
||||||
}
|
}
|
||||||
|
|
||||||
// transmit the dirty region
|
int32_t bufIdx = SurfaceBuffer::getSelf(buffer)->getIndex();
|
||||||
SurfaceID index(mToken);
|
mSharedBufferClient->setDirtyRegion(bufIdx, mDirtyRegion);
|
||||||
layer_cblk_t* const lcblk = &(cblk->layers[index]);
|
err = mSharedBufferClient->queue(bufIdx);
|
||||||
_send_dirty_region(lcblk, mDirtyRegion);
|
LOGE_IF(err, "error queuing buffer %d (%s)", bufIdx, strerror(-err));
|
||||||
|
|
||||||
uint32_t newstate = cblk->unlock_layer_and_post(size_t(index));
|
if (err == NO_ERROR) {
|
||||||
if (!(newstate & eNextFlipPending))
|
// FIXME: can we avoid this IPC if we know there is one pending?
|
||||||
client->signalServer();
|
client->signalServer();
|
||||||
|
}
|
||||||
return NO_ERROR;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Surface::query(int what, int* value)
|
int Surface::query(int what, int* value)
|
||||||
{
|
{
|
||||||
switch (what) {
|
switch (what) {
|
||||||
case NATIVE_WINDOW_WIDTH:
|
case NATIVE_WINDOW_WIDTH:
|
||||||
*value = int(mWidth);
|
*value = int(mWidth);
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
case NATIVE_WINDOW_HEIGHT:
|
case NATIVE_WINDOW_HEIGHT:
|
||||||
*value = int(mHeight);
|
*value = int(mHeight);
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
case NATIVE_WINDOW_FORMAT:
|
case NATIVE_WINDOW_FORMAT:
|
||||||
*value = int(mFormat);
|
*value = int(mFormat);
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
return BAD_VALUE;
|
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) {
|
status_t Surface::lock(SurfaceInfo* info, bool blocking) {
|
||||||
@@ -723,13 +625,24 @@ status_t Surface::lock(SurfaceInfo* info, bool blocking) {
|
|||||||
|
|
||||||
status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, 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
|
// we're intending to do software rendering from this point
|
||||||
setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
|
setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
|
||||||
|
|
||||||
sp<SurfaceBuffer> backBuffer;
|
sp<SurfaceBuffer> backBuffer;
|
||||||
status_t err = dequeueBuffer(&backBuffer);
|
status_t err = dequeueBuffer(&backBuffer);
|
||||||
|
LOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
|
||||||
if (err == NO_ERROR) {
|
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) {
|
if (err == NO_ERROR) {
|
||||||
// we handle copy-back here...
|
// we handle copy-back here...
|
||||||
|
|
||||||
@@ -737,29 +650,30 @@ status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking)
|
|||||||
Region scratch(bounds);
|
Region scratch(bounds);
|
||||||
Region& newDirtyRegion(dirtyIn ? *dirtyIn : scratch);
|
Region& newDirtyRegion(dirtyIn ? *dirtyIn : scratch);
|
||||||
|
|
||||||
sp<SurfaceComposerClient> client(getClient());
|
if (mNeedFullUpdate) {
|
||||||
per_client_cblk_t* const cblk = client->mControl;
|
// reset newDirtyRegion to bounds when a buffer is reallocated
|
||||||
layer_cblk_t* const lcblk = &(cblk->layers[SurfaceID(mToken)]);
|
// it would be better if this information was associated with
|
||||||
volatile const surface_info_t* const back = lcblk->surface + mBackbufferIndex;
|
// the buffer and made available to outside of Surface.
|
||||||
if (back->flags & surface_info_t::eBufferDirty) {
|
// This will do for now though.
|
||||||
// content is meaningless in this case and the whole surface
|
mNeedFullUpdate = false;
|
||||||
// needs to be redrawn.
|
|
||||||
newDirtyRegion.set(bounds);
|
newDirtyRegion.set(bounds);
|
||||||
} else {
|
} else {
|
||||||
newDirtyRegion.andSelf(bounds);
|
newDirtyRegion.andSelf(bounds);
|
||||||
const sp<SurfaceBuffer>& frontBuffer(mBuffers[1-mBackbufferIndex]);
|
}
|
||||||
if (frontBuffer !=0 &&
|
|
||||||
backBuffer->width == frontBuffer->width &&
|
const sp<SurfaceBuffer>& frontBuffer(mPostedBuffer);
|
||||||
backBuffer->height == frontBuffer->height &&
|
if (frontBuffer !=0 &&
|
||||||
!(lcblk->flags & eNoCopyBack))
|
backBuffer->width == frontBuffer->width &&
|
||||||
{
|
backBuffer->height == frontBuffer->height &&
|
||||||
const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));
|
!(mFlags & ISurfaceComposer::eDestroyBackbuffer))
|
||||||
if (!copyback.isEmpty() && frontBuffer!=0) {
|
{
|
||||||
// copy front to back
|
const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));
|
||||||
copyBlt(backBuffer, frontBuffer, copyback);
|
if (!copyback.isEmpty() && frontBuffer!=0) {
|
||||||
}
|
// copy front to back
|
||||||
|
copyBlt(backBuffer, frontBuffer, copyback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mDirtyRegion = newDirtyRegion;
|
mDirtyRegion = newDirtyRegion;
|
||||||
mOldDirtyRegion = 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,
|
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
|
||||||
newDirtyRegion.bounds(), &vaddr);
|
newDirtyRegion.bounds(), &vaddr);
|
||||||
|
|
||||||
LOGW_IF(res, "failed locking buffer %d (%p)",
|
LOGW_IF(res, "failed locking buffer (handle = %p)",
|
||||||
mBackbufferIndex, backBuffer->handle);
|
backBuffer->handle);
|
||||||
|
|
||||||
mLockedBuffer = backBuffer;
|
mLockedBuffer = backBuffer;
|
||||||
other->w = backBuffer->width;
|
other->w = backBuffer->width;
|
||||||
@@ -780,36 +694,29 @@ status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking)
|
|||||||
other->bits = vaddr;
|
other->bits = vaddr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mApiLock.unlock();
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t Surface::unlockAndPost()
|
status_t Surface::unlockAndPost()
|
||||||
{
|
{
|
||||||
if (mLockedBuffer == 0)
|
if (mLockedBuffer == 0) {
|
||||||
|
LOGE("unlockAndPost failed, no locked buffer");
|
||||||
return BAD_VALUE;
|
return BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
status_t res = mLockedBuffer->unlock();
|
status_t err = mLockedBuffer->unlock();
|
||||||
LOGW_IF(res, "failed unlocking buffer %d (%p)",
|
LOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
|
||||||
mBackbufferIndex, 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;
|
mLockedBuffer = 0;
|
||||||
return err;
|
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) {
|
void Surface::setSwapRectangle(const Rect& r) {
|
||||||
Mutex::Autolock _l(mSurfaceLock);
|
Mutex::Autolock _l(mSurfaceLock);
|
||||||
mSwapRectangle = r;
|
mSwapRectangle = r;
|
||||||
@@ -829,15 +736,22 @@ status_t Surface::getBufferLocked(int index, int usage)
|
|||||||
currentBuffer.clear();
|
currentBuffer.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
sp<SurfaceBuffer> buffer = s->getBuffer(usage);
|
sp<SurfaceBuffer> buffer = s->requestBuffer(index, usage);
|
||||||
LOGE_IF(buffer==0, "ISurface::getBuffer() returned NULL");
|
LOGE_IF(buffer==0,
|
||||||
|
"ISurface::getBuffer(%d, %08x) returned NULL",
|
||||||
|
index, usage);
|
||||||
if (buffer != 0) { // this should never happen by construction
|
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) {
|
if (buffer->handle != NULL) {
|
||||||
err = getBufferMapper().registerBuffer(buffer->handle);
|
err = getBufferMapper().registerBuffer(buffer->handle);
|
||||||
LOGW_IF(err, "registerBuffer(...) failed %d (%s)",
|
LOGW_IF(err, "registerBuffer(...) failed %d (%s)",
|
||||||
err, strerror(-err));
|
err, strerror(-err));
|
||||||
if (err == NO_ERROR) {
|
if (err == NO_ERROR) {
|
||||||
currentBuffer = buffer;
|
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/SurfaceComposerClient.h>
|
||||||
#include <ui/Rect.h>
|
#include <ui/Rect.h>
|
||||||
|
|
||||||
#include <private/ui/SharedState.h>
|
|
||||||
#include <private/ui/LayerState.h>
|
#include <private/ui/LayerState.h>
|
||||||
|
#include <private/ui/SharedBufferStack.h>
|
||||||
#include <private/ui/SurfaceFlingerSynchro.h>
|
#include <private/ui/SurfaceFlingerSynchro.h>
|
||||||
|
|
||||||
#define VERBOSE(...) ((void)0)
|
#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,
|
static inline int compare_type( const layer_state_t& lhs,
|
||||||
const layer_state_t& rhs) {
|
const layer_state_t& rhs) {
|
||||||
if (lhs.surface < rhs.surface) return -1;
|
if (lhs.surface < rhs.surface) return -1;
|
||||||
@@ -315,7 +152,7 @@ void SurfaceComposerClient::_init(
|
|||||||
|
|
||||||
mControlMemory = mClient->getControlBlock();
|
mControlMemory = mClient->getControlBlock();
|
||||||
mSignalServer = new SurfaceFlingerSynchro(sm);
|
mSignalServer = new SurfaceFlingerSynchro(sm);
|
||||||
mControl = static_cast<per_client_cblk_t *>(mControlMemory->getBase());
|
mControl = static_cast<SharedClient *>(mControlMemory->getBase());
|
||||||
}
|
}
|
||||||
|
|
||||||
SurfaceComposerClient::~SurfaceComposerClient()
|
SurfaceComposerClient::~SurfaceComposerClient()
|
||||||
@@ -539,18 +376,17 @@ void SurfaceComposerClient::closeGlobalTransaction()
|
|||||||
|
|
||||||
const size_t N = clients.size();
|
const size_t N = clients.size();
|
||||||
VERBOSE("closeGlobalTransaction (%ld clients)", N);
|
VERBOSE("closeGlobalTransaction (%ld clients)", N);
|
||||||
if (N == 1) {
|
|
||||||
clients[0]->closeTransaction();
|
const sp<ISurfaceComposer>& sm(_get_surface_manager());
|
||||||
} else {
|
sm->openGlobalTransaction();
|
||||||
const sp<ISurfaceComposer>& sm(_get_surface_manager());
|
for (size_t i=0; i<N; i++) {
|
||||||
sm->openGlobalTransaction();
|
clients[i]->closeTransaction();
|
||||||
for (size_t i=0; i<N; i++) {
|
|
||||||
clients[i]->closeTransaction();
|
|
||||||
}
|
|
||||||
sm->closeGlobalTransaction();
|
|
||||||
}
|
}
|
||||||
|
sm->closeGlobalTransaction();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t SurfaceComposerClient::freezeDisplay(DisplayID dpy, uint32_t flags)
|
status_t SurfaceComposerClient::freezeDisplay(DisplayID dpy, uint32_t flags)
|
||||||
{
|
{
|
||||||
const sp<ISurfaceComposer>& sm(_get_surface_manager());
|
const sp<ISurfaceComposer>& sm(_get_surface_manager());
|
||||||
|
|||||||
Reference in New Issue
Block a user