unify SurfaceTexture and Surface

Add the concept of synchronous dequeueBuffer in SurfaceTexture
Implement {Surface|SurfaceTextureClient}::setSwapInterval()
Add SurfaceTexture logging
fix onFrameAvailable
This commit is contained in:
Mathias Agopian 2011-04-20 14:20:59 -07:00
parent ac642349ba
commit a67932fe68
27 changed files with 607 additions and 3125 deletions

View File

@ -20,355 +20,12 @@
#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.
*
*/
// ----------------------------------------------------------------------------
class Region;
class SharedBufferStack;
class SharedClient;
// ----------------------------------------------------------------------------
class SharedBufferStack
{
friend class SharedClient;
friend class SharedBufferBase;
friend class SharedBufferClient;
friend class SharedBufferServer;
public:
// When changing these values, the COMPILE_TIME_ASSERT at the end of this
// file need to be updated.
static const unsigned int NUM_LAYERS_MAX = 31;
static const unsigned int NUM_BUFFER_MAX = 32;
static const unsigned int NUM_BUFFER_MIN = 2;
static const unsigned int NUM_DISPLAY_MAX = 4;
struct Statistics { // 4 longs
typedef int32_t usecs_t;
usecs_t totalTime;
usecs_t reserved[3];
};
struct SmallRect {
uint16_t l, t, r, b;
};
struct FlatRegion { // 52 bytes = 4 * (1 + 2*N)
static const unsigned int NUM_RECT_MAX = 5;
uint32_t count;
SmallRect rects[NUM_RECT_MAX];
};
struct BufferData {
FlatRegion dirtyRegion;
SmallRect crop;
uint8_t transform;
uint8_t reserved[3];
};
SharedBufferStack();
void init(int32_t identity);
status_t setDirtyRegion(int buffer, const Region& reg);
status_t setCrop(int buffer, const Rect& reg);
status_t setTransform(int buffer, uint8_t transform);
Region getDirtyRegion(int buffer) const;
Rect getCrop(int buffer) const;
uint32_t getTransform(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 reserved1;
volatile status_t status; // surface's status code
// not part of the conditions
volatile int32_t reallocMask;
volatile int8_t index[NUM_BUFFER_MAX];
int32_t identity; // surface's identity (const)
int32_t token; // surface's token (for debugging)
Statistics stats;
int8_t headBuf; // last retired buffer
uint8_t reservedBytes[3];
int32_t reserved;
BufferData buffers[NUM_BUFFER_MAX]; // 1024 bytes
};
// ----------------------------------------------------------------------------
// 64 KB max
class SharedClient
{
public:
SharedClient();
~SharedClient();
status_t validate(size_t token) const;
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[ SharedBufferStack::NUM_LAYERS_MAX ];
};
// ============================================================================
class SharedBufferBase
{
public:
SharedBufferBase(SharedClient* sharedClient, int surface,
int32_t identity);
~SharedBufferBase();
status_t getStatus() const;
int32_t getIdentity() const;
String8 dump(char const* prefix) const;
protected:
SharedClient* const mSharedClient;
SharedBufferStack* const mSharedStack;
const int mIdentity;
friend struct Update;
friend struct QueueUpdate;
struct ConditionBase {
SharedBufferStack& stack;
inline ConditionBase(SharedBufferBase* sbc)
: stack(*sbc->mSharedStack) { }
virtual ~ConditionBase() { };
virtual bool operator()() const = 0;
virtual const char* name() const = 0;
};
status_t waitForCondition(const ConditionBase& condition);
struct UpdateBase {
SharedBufferStack& stack;
inline UpdateBase(SharedBufferBase* sbb)
: stack(*sbb->mSharedStack) { }
};
template <typename T>
status_t updateCondition(T update);
};
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,
int32_t identity);
ssize_t dequeue();
status_t undoDequeue(int buf);
status_t lock(int buf);
status_t cancel(int buf);
status_t queue(int buf);
bool needNewBuffer(int buffer) const;
status_t setDirtyRegion(int buffer, const Region& reg);
status_t setCrop(int buffer, const Rect& reg);
status_t setTransform(int buffer, uint32_t transform);
class SetBufferCountCallback {
friend class SharedBufferClient;
virtual status_t operator()(int bufferCount) const = 0;
protected:
virtual ~SetBufferCountCallback() { }
};
status_t setBufferCount(int bufferCount, const SetBufferCountCallback& ipc);
private:
friend struct Condition;
friend struct DequeueCondition;
friend struct LockCondition;
struct QueueUpdate : public UpdateBase {
inline QueueUpdate(SharedBufferBase* sbb);
inline ssize_t operator()();
};
struct DequeueUpdate : public UpdateBase {
inline DequeueUpdate(SharedBufferBase* sbb);
inline ssize_t operator()();
};
struct CancelUpdate : public UpdateBase {
int tail, buf;
inline CancelUpdate(SharedBufferBase* sbb, int tail, int buf);
inline ssize_t operator()();
};
// --
struct DequeueCondition : public ConditionBase {
inline DequeueCondition(SharedBufferClient* sbc);
inline bool operator()() const;
inline const char* name() const { return "DequeueCondition"; }
};
struct LockCondition : public ConditionBase {
int buf;
inline LockCondition(SharedBufferClient* sbc, int buf);
inline bool operator()() const;
inline const char* name() const { return "LockCondition"; }
};
int32_t computeTail() const;
mutable RWLock mLock;
int mNumBuffers;
int32_t tail;
int32_t queued_head;
// statistics...
nsecs_t mDequeueTime[SharedBufferStack::NUM_BUFFER_MAX];
};
// ----------------------------------------------------------------------------
class SharedBufferServer
: public SharedBufferBase,
public LightRefBase<SharedBufferServer>
{
public:
SharedBufferServer(SharedClient* sharedClient, int surface, int num,
int32_t identity);
ssize_t retireAndLock();
void setStatus(status_t status);
status_t reallocateAll();
status_t reallocateAllExcept(int buffer);
int32_t getQueuedCount() const;
Region getDirtyRegion(int buffer) const;
Rect getCrop(int buffer) const;
uint32_t getTransform(int buffer) const;
status_t resize(int newNumBuffers);
status_t grow(int newNumBuffers);
status_t shrink(int newNumBuffers);
SharedBufferStack::Statistics getStats() const;
private:
friend class LightRefBase<SharedBufferServer>;
~SharedBufferServer();
/*
* BufferList is basically a fixed-capacity sorted-vector of
* unsigned 5-bits ints using a 32-bits int as storage.
* it has efficient iterators to find items in the list and not in the list.
*/
class BufferList {
size_t mCapacity;
uint32_t mList;
public:
BufferList(size_t c = SharedBufferStack::NUM_BUFFER_MAX)
: mCapacity(c), mList(0) { }
status_t add(int value);
status_t remove(int value);
uint32_t getMask() const { return mList; }
class const_iterator {
friend class BufferList;
uint32_t mask, curr;
const_iterator(uint32_t mask) :
mask(mask), curr(__builtin_clz(mask)) {
}
public:
inline bool operator == (const const_iterator& rhs) const {
return mask == rhs.mask;
}
inline bool operator != (const const_iterator& rhs) const {
return mask != rhs.mask;
}
inline int operator *() const { return curr; }
inline const const_iterator& operator ++() {
mask &= ~(1<<(31-curr));
curr = __builtin_clz(mask);
return *this;
}
};
inline const_iterator begin() const {
return const_iterator(mList);
}
inline const_iterator end() const {
return const_iterator(0);
}
inline const_iterator free_begin() const {
uint32_t mask = (1 << (32-mCapacity)) - 1;
return const_iterator( ~(mList | mask) );
}
};
// this protects mNumBuffers and mBufferList
mutable RWLock mLock;
int mNumBuffers;
BufferList mBufferList;
struct BuffersAvailableCondition : public ConditionBase {
int mNumBuffers;
inline BuffersAvailableCondition(SharedBufferServer* sbs,
int numBuffers);
inline bool operator()() const;
inline const char* name() const { return "BuffersAvailableCondition"; }
};
struct RetireUpdate : public UpdateBase {
const int numBuffers;
inline RetireUpdate(SharedBufferBase* sbb, int numBuffers);
inline ssize_t operator()();
};
struct StatusUpdate : public UpdateBase {
const status_t status;
inline StatusUpdate(SharedBufferBase* sbb, status_t status);
inline ssize_t operator()();
};
};
// ===========================================================================
#define NUM_DISPLAY_MAX 4
struct display_cblk_t
{
@ -389,12 +46,11 @@ struct surface_flinger_cblk_t // 4KB max
uint8_t connected;
uint8_t reserved[3];
uint32_t pad[7];
display_cblk_t displays[SharedBufferStack::NUM_DISPLAY_MAX];
display_cblk_t displays[NUM_DISPLAY_MAX];
};
// ---------------------------------------------------------------------------
COMPILE_TIME_ASSERT(sizeof(SharedClient) <= 65536)
COMPILE_TIME_ASSERT(sizeof(surface_flinger_cblk_t) <= 4096)
// ---------------------------------------------------------------------------

View File

@ -27,6 +27,8 @@
namespace android {
// ----------------------------------------------------------------------------
class GraphicBuffer;
class IGraphicBufferAlloc : public IInterface
{
public:

View File

@ -27,42 +27,23 @@
#include <ui/PixelFormat.h>
#include <hardware/hardware.h>
#include <hardware/gralloc.h>
namespace android {
typedef int32_t SurfaceID;
class GraphicBuffer;
class ISurfaceTexture;
class ISurface : public IInterface
{
protected:
enum {
RESERVED0 = IBinder::FIRST_CALL_TRANSACTION,
RESERVED1,
RESERVED2,
REQUEST_BUFFER,
SET_BUFFER_COUNT,
GET_SURFACE_TEXTURE = IBinder::FIRST_CALL_TRANSACTION,
};
public:
DECLARE_META_INTERFACE(Surface);
/*
* requests a new buffer for the given index. If w, h, or format are
* null the buffer is created with the parameters assigned to the
* surface it is bound to. Otherwise the buffer's parameters are
* set to those specified.
*/
virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage) = 0;
/*
* sets the number of buffers dequeuable for this surface.
*/
virtual status_t setBufferCount(int bufferCount) = 0;
virtual sp<ISurfaceTexture> getSurfaceTexture() const = 0;
};
// ----------------------------------------------------------------------------

View File

@ -33,6 +33,8 @@
namespace android {
// ----------------------------------------------------------------------------
class IMemoryHeap;
class ISurfaceComposer : public IInterface
{
public:
@ -95,10 +97,6 @@ public:
*/
virtual sp<ISurfaceComposerClient> createConnection() = 0;
/* create a client connection with surface flinger
*/
virtual sp<ISurfaceComposerClient> createClientConnection() = 0;
/* create a graphic buffer allocator
*/
virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc() = 0;
@ -134,11 +132,6 @@ public:
virtual status_t turnElectronBeamOff(int32_t mode) = 0;
virtual status_t turnElectronBeamOn(int32_t mode) = 0;
/* Signal surfaceflinger that there might be some work to do
* This is an ASYNCHRONOUS call.
*/
virtual void signal() const = 0;
/* verify that an ISurface was created by SurfaceFlinger.
*/
virtual bool authenticateSurface(const sp<ISurface>& surface) const = 0;
@ -154,7 +147,6 @@ public:
// Java by ActivityManagerService.
BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
CREATE_CONNECTION,
CREATE_CLIENT_CONNECTION,
CREATE_GRAPHIC_BUFFER_ALLOC,
GET_CBLK,
OPEN_GLOBAL_TRANSACTION,
@ -162,7 +154,6 @@ public:
SET_ORIENTATION,
FREEZE_DISPLAY,
UNFREEZE_DISPLAY,
SIGNAL,
CAPTURE_SCREEN,
TURN_ELECTRON_BEAM_OFF,
TURN_ELECTRON_BEAM_ON,

View File

@ -33,9 +33,6 @@ namespace android {
// ----------------------------------------------------------------------------
class IMemoryHeap;
typedef int32_t ClientID;
typedef int32_t DisplayID;
// ----------------------------------------------------------------------------
@ -57,9 +54,6 @@ public:
status_t writeToParcel(Parcel* parcel) const;
};
virtual sp<IMemoryHeap> getControlBlock() const = 0;
virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const = 0;
/*
* Requires ACCESS_SURFACE_FLINGER permission
*/

View File

@ -43,9 +43,7 @@ class IOMX;
class Rect;
class Surface;
class SurfaceComposerClient;
class SharedClient;
class SharedBufferClient;
class SurfaceClient;
class SurfaceTextureClient;
// ---------------------------------------------------------------------------
@ -162,9 +160,6 @@ public:
status_t lock(SurfaceInfo* info, Region* dirty, bool blocking = true);
status_t unlockAndPost();
// setSwapRectangle() is intended to be used by GL ES clients
void setSwapRectangle(const Rect& r);
sp<IBinder> asBinder() const;
private:
@ -209,6 +204,7 @@ private:
static int query(const ANativeWindow* window, int what, int* value);
static int perform(ANativeWindow* window, int operation, ...);
int setSwapInterval(int interval);
int dequeueBuffer(ANativeWindowBuffer** buffer);
int lockBuffer(ANativeWindowBuffer* buffer);
int queueBuffer(ANativeWindowBuffer* buffer);
@ -216,83 +212,23 @@ private:
int query(int what, int* value) const;
int perform(int operation, va_list args);
void dispatch_setUsage(va_list args);
int dispatch_connect(va_list args);
int dispatch_disconnect(va_list args);
int dispatch_crop(va_list args);
int dispatch_set_buffer_count(va_list args);
int dispatch_set_buffers_geometry(va_list args);
int dispatch_set_buffers_transform(va_list args);
int dispatch_set_buffers_timestamp(va_list args);
void setUsage(uint32_t reqUsage);
int connect(int api);
int disconnect(int api);
int crop(Rect const* rect);
int setBufferCount(int bufferCount);
int setBuffersGeometry(int w, int h, int format);
int setBuffersTransform(int transform);
int setBuffersTimestamp(int64_t timestamp);
/*
* private stuff...
*/
void init();
status_t validate(bool inCancelBuffer = false) const;
// When the buffer pool is a fixed size we want to make sure SurfaceFlinger
// won't stall clients, so we require an extra buffer.
enum { MIN_UNDEQUEUED_BUFFERS = 2 };
inline const GraphicBufferMapper& getBufferMapper() const { return mBufferMapper; }
inline GraphicBufferMapper& getBufferMapper() { return mBufferMapper; }
status_t getBufferLocked(int index,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
int getBufferIndex(const sp<GraphicBuffer>& buffer) const;
int getConnectedApi() const;
bool needNewBuffer(int bufIdx,
uint32_t *pWidth, uint32_t *pHeight,
uint32_t *pFormat, uint32_t *pUsage) const;
static void cleanCachedSurfacesLocked();
class BufferInfo {
uint32_t mWidth;
uint32_t mHeight;
uint32_t mFormat;
uint32_t mUsage;
mutable uint32_t mDirty;
enum {
GEOMETRY = 0x01
};
public:
BufferInfo();
void set(uint32_t w, uint32_t h, uint32_t format);
void set(uint32_t usage);
void get(uint32_t *pWidth, uint32_t *pHeight,
uint32_t *pFormat, uint32_t *pUsage) const;
bool validateBuffer(const sp<GraphicBuffer>& buffer) const;
};
// constants
GraphicBufferMapper& mBufferMapper;
SurfaceClient& mClient;
SharedBufferClient* mSharedBufferClient;
status_t mInitCheck;
sp<ISurface> mSurface;
sp<SurfaceTextureClient> mSurfaceTextureClient;
uint32_t mIdentity;
PixelFormat mFormat;
uint32_t mFlags;
// protected by mSurfaceLock
Rect mSwapRectangle;
int mConnected;
Rect mNextBufferCrop;
uint32_t mNextBufferTransform;
BufferInfo mBufferInfo;
// protected by mSurfaceLock. These are also used from lock/unlock
// but in that case, they must be called form the same thread.
@ -304,9 +240,6 @@ private:
mutable Region mOldDirtyRegion;
bool mReserved;
// only used from dequeueBuffer()
Vector< sp<GraphicBuffer> > mBuffers;
// query() must be called from dequeueBuffer() thread
uint32_t mWidth;
uint32_t mHeight;

View File

@ -36,10 +36,10 @@ namespace android {
// ---------------------------------------------------------------------------
class Region;
class SharedClient;
class ISurfaceComposer;
class DisplayInfo;
class IMemoryHeap;
class ISurfaceComposer;
class Region;
class surface_flinger_cblk_t;
// ---------------------------------------------------------------------------

View File

@ -16,7 +16,6 @@ LOCAL_SRC_FILES:= \
ISurfaceComposerClient.cpp \
IGraphicBufferAlloc.cpp \
LayerState.cpp \
SharedBufferStack.cpp \
Surface.cpp \
SurfaceComposerClient.cpp \

View File

@ -22,9 +22,7 @@
#include <binder/Parcel.h>
#include <ui/GraphicBuffer.h>
#include <surfaceflinger/Surface.h>
#include <gui/ISurfaceTexture.h>
#include <surfaceflinger/ISurface.h>
namespace android {
@ -39,30 +37,11 @@ public:
{
}
virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage)
{
virtual sp<ISurfaceTexture> getSurfaceTexture() const {
Parcel data, reply;
data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
data.writeInt32(bufferIdx);
data.writeInt32(w);
data.writeInt32(h);
data.writeInt32(format);
data.writeInt32(usage);
remote()->transact(REQUEST_BUFFER, data, &reply);
sp<GraphicBuffer> buffer = new GraphicBuffer();
reply.read(*buffer);
return buffer;
}
virtual status_t setBufferCount(int bufferCount)
{
Parcel data, reply;
data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
data.writeInt32(bufferCount);
remote()->transact(SET_BUFFER_COUNT, data, &reply);
status_t err = reply.readInt32();
return err;
remote()->transact(GET_SURFACE_TEXTURE, data, &reply);
return interface_cast<ISurfaceTexture>(reply.readStrongBinder());
}
};
@ -74,23 +53,9 @@ status_t BnSurface::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
case REQUEST_BUFFER: {
case GET_SURFACE_TEXTURE: {
CHECK_INTERFACE(ISurface, data, reply);
int bufferIdx = data.readInt32();
uint32_t w = data.readInt32();
uint32_t h = data.readInt32();
uint32_t format = data.readInt32();
uint32_t usage = data.readInt32();
sp<GraphicBuffer> buffer(requestBuffer(bufferIdx, w, h, format, usage));
if (buffer == NULL)
return BAD_VALUE;
return reply->write(*buffer);
}
case SET_BUFFER_COUNT: {
CHECK_INTERFACE(ISurface, data, reply);
int bufferCount = data.readInt32();
status_t err = setBufferCount(bufferCount);
reply->writeInt32(err);
reply->writeStrongBinder( getSurfaceTexture()->asBinder() );
return NO_ERROR;
}
default:

View File

@ -57,15 +57,6 @@ public:
return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder());
}
virtual sp<ISurfaceComposerClient> createClientConnection()
{
uint32_t n;
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
remote()->transact(BnSurfaceComposer::CREATE_CLIENT_CONNECTION, data, &reply);
return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder());
}
virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc()
{
uint32_t n;
@ -174,13 +165,6 @@ public:
return reply.readInt32();
}
virtual void signal() const
{
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
remote()->transact(BnSurfaceComposer::SIGNAL, data, &reply, IBinder::FLAG_ONEWAY);
}
virtual bool authenticateSurface(const sp<ISurface>& surface) const
{
Parcel data, reply;
@ -229,11 +213,6 @@ status_t BnSurfaceComposer::onTransact(
sp<IBinder> b = createConnection()->asBinder();
reply->writeStrongBinder(b);
} break;
case CREATE_CLIENT_CONNECTION: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> b = createClientConnection()->asBinder();
reply->writeStrongBinder(b);
} break;
case CREATE_GRAPHIC_BUFFER_ALLOC: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> b = createGraphicBufferAlloc()->asBinder();
@ -270,10 +249,6 @@ status_t BnSurfaceComposer::onTransact(
CHECK_INTERFACE(ISurfaceComposer, data, reply);
bootFinished();
} break;
case SIGNAL: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
signal();
} break;
case GET_CBLK: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> b = getCblk()->asBinder();

View File

@ -50,9 +50,7 @@
namespace android {
enum {
GET_CBLK = IBinder::FIRST_CALL_TRANSACTION,
GET_TOKEN,
CREATE_SURFACE,
CREATE_SURFACE = IBinder::FIRST_CALL_TRANSACTION,
DESTROY_SURFACE,
SET_STATE
};
@ -65,23 +63,6 @@ public:
{
}
virtual sp<IMemoryHeap> getControlBlock() const
{
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
remote()->transact(GET_CBLK, data, &reply);
return interface_cast<IMemoryHeap>(reply.readStrongBinder());
}
virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const
{
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
data.writeStrongBinder(sur->asBinder());
remote()->transact(GET_TOKEN, data, &reply);
return reply.readInt32();
}
virtual sp<ISurface> createSurface( surface_data_t* params,
const String8& name,
DisplayID display,
@ -131,41 +112,6 @@ IMPLEMENT_META_INTERFACE(SurfaceComposerClient, "android.ui.ISurfaceComposerClie
status_t BnSurfaceComposerClient::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
// codes that don't require permission check
switch(code) {
case GET_CBLK: {
CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
sp<IMemoryHeap> ctl(getControlBlock());
reply->writeStrongBinder(ctl->asBinder());
return NO_ERROR;
} break;
case GET_TOKEN: {
CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
sp<ISurface> sur = interface_cast<ISurface>(data.readStrongBinder());
ssize_t token = getTokenForSurface(sur);
reply->writeInt32(token);
return NO_ERROR;
} break;
}
// these must be checked
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
const int uid = ipc->getCallingUid();
const int self_pid = getpid();
if (UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != 0)) {
// we're called from a different process, do the real check
if (!checkCallingPermission(
String16("android.permission.ACCESS_SURFACE_FLINGER")))
{
LOGE("Permission Denial: "
"can't openGlobalTransaction pid=%d, uid=%d", pid, uid);
return PERMISSION_DENIED;
}
}
switch(code) {
case CREATE_SURFACE: {
CHECK_INTERFACE(ISurfaceComposerClient, data, reply);

View File

@ -1,714 +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 "SharedBufferStack"
#include <stdint.h>
#include <sys/types.h>
#include <utils/Debug.h>
#include <utils/Log.h>
#include <utils/threads.h>
#include <private/surfaceflinger/SharedBufferStack.h>
#include <ui/Rect.h>
#include <ui/Region.h>
#define DEBUG_ATOMICS 0
namespace android {
// ----------------------------------------------------------------------------
SharedClient::SharedClient()
: lock(Mutex::SHARED), cv(Condition::SHARED)
{
}
SharedClient::~SharedClient() {
}
// these functions are used by the clients
status_t SharedClient::validate(size_t i) const {
if (uint32_t(i) >= uint32_t(SharedBufferStack::NUM_LAYERS_MAX))
return BAD_INDEX;
return surfaces[i].status;
}
// ----------------------------------------------------------------------------
SharedBufferStack::SharedBufferStack()
{
}
void SharedBufferStack::init(int32_t i)
{
status = NO_ERROR;
identity = i;
}
status_t SharedBufferStack::setCrop(int buffer, const Rect& crop)
{
if (uint32_t(buffer) >= NUM_BUFFER_MAX)
return BAD_INDEX;
buffers[buffer].crop.l = uint16_t(crop.left);
buffers[buffer].crop.t = uint16_t(crop.top);
buffers[buffer].crop.r = uint16_t(crop.right);
buffers[buffer].crop.b = uint16_t(crop.bottom);
return NO_ERROR;
}
status_t SharedBufferStack::setTransform(int buffer, uint8_t transform)
{
if (uint32_t(buffer) >= NUM_BUFFER_MAX)
return BAD_INDEX;
buffers[buffer].transform = transform;
return NO_ERROR;
}
status_t SharedBufferStack::setDirtyRegion(int buffer, const Region& dirty)
{
if (uint32_t(buffer) >= NUM_BUFFER_MAX)
return BAD_INDEX;
FlatRegion& reg(buffers[buffer].dirtyRegion);
if (dirty.isEmpty()) {
reg.count = 0;
return NO_ERROR;
}
size_t count;
Rect const* r = dirty.getArray(&count);
if (count > FlatRegion::NUM_RECT_MAX) {
const Rect bounds(dirty.getBounds());
reg.count = 1;
reg.rects[0].l = uint16_t(bounds.left);
reg.rects[0].t = uint16_t(bounds.top);
reg.rects[0].r = uint16_t(bounds.right);
reg.rects[0].b = uint16_t(bounds.bottom);
} else {
reg.count = count;
for (size_t i=0 ; i<count ; i++) {
reg.rects[i].l = uint16_t(r[i].left);
reg.rects[i].t = uint16_t(r[i].top);
reg.rects[i].r = uint16_t(r[i].right);
reg.rects[i].b = uint16_t(r[i].bottom);
}
}
return NO_ERROR;
}
Region SharedBufferStack::getDirtyRegion(int buffer) const
{
Region res;
if (uint32_t(buffer) >= NUM_BUFFER_MAX)
return res;
const FlatRegion& reg(buffers[buffer].dirtyRegion);
if (reg.count > FlatRegion::NUM_RECT_MAX)
return res;
if (reg.count == 1) {
const Rect r(
reg.rects[0].l,
reg.rects[0].t,
reg.rects[0].r,
reg.rects[0].b);
res.set(r);
} else {
for (size_t i=0 ; i<reg.count ; i++) {
const Rect r(
reg.rects[i].l,
reg.rects[i].t,
reg.rects[i].r,
reg.rects[i].b);
res.orSelf(r);
}
}
return res;
}
Rect SharedBufferStack::getCrop(int buffer) const
{
Rect res(-1, -1);
if (uint32_t(buffer) >= NUM_BUFFER_MAX)
return res;
res.left = buffers[buffer].crop.l;
res.top = buffers[buffer].crop.t;
res.right = buffers[buffer].crop.r;
res.bottom = buffers[buffer].crop.b;
return res;
}
uint32_t SharedBufferStack::getTransform(int buffer) const
{
if (uint32_t(buffer) >= NUM_BUFFER_MAX)
return 0;
return buffers[buffer].transform;
}
// ----------------------------------------------------------------------------
SharedBufferBase::SharedBufferBase(SharedClient* sharedClient,
int surface, int32_t identity)
: mSharedClient(sharedClient),
mSharedStack(sharedClient->surfaces + surface),
mIdentity(identity)
{
}
SharedBufferBase::~SharedBufferBase()
{
}
status_t SharedBufferBase::getStatus() const
{
SharedBufferStack& stack( *mSharedStack );
return stack.status;
}
int32_t SharedBufferBase::getIdentity() const
{
SharedBufferStack& stack( *mSharedStack );
return stack.identity;
}
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, identity=%d, status=%d",
prefix, stack.head, stack.available, stack.queued,
stack.reallocMask, stack.identity, stack.status);
result.append(buffer);
result.append("\n");
return result;
}
status_t SharedBufferBase::waitForCondition(const ConditionBase& condition)
{
const SharedBufferStack& stack( *mSharedStack );
SharedClient& client( *mSharedClient );
const nsecs_t TIMEOUT = s2ns(1);
const int identity = mIdentity;
Mutex::Autolock _l(client.lock);
while ((condition()==false) &&
(stack.identity == identity) &&
(stack.status == NO_ERROR))
{
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." , condition.name(), stack.identity);
break;
} else {
LOGW("waitForCondition(%s) timed out "
"(identity=%d, status=%d). "
"CPU may be pegged. trying again.", condition.name(),
stack.identity, stack.status);
}
} else {
LOGE("waitForCondition(%s) error (%s) ",
condition.name(), strerror(-err));
return err;
}
}
}
return (stack.identity != mIdentity) ? status_t(BAD_INDEX) : stack.status;
}
// ============================================================================
// conditions and updates
// ============================================================================
SharedBufferClient::DequeueCondition::DequeueCondition(
SharedBufferClient* sbc) : ConditionBase(sbc) {
}
bool SharedBufferClient::DequeueCondition::operator()() const {
return stack.available > 0;
}
SharedBufferClient::LockCondition::LockCondition(
SharedBufferClient* sbc, int buf) : ConditionBase(sbc), buf(buf) {
}
bool SharedBufferClient::LockCondition::operator()() const {
// NOTE: if stack.head is messed up, we could crash the client
// or cause some drawing artifacts. This is okay, as long as it is
// limited to the client.
return (buf != stack.index[stack.head]);
}
SharedBufferServer::BuffersAvailableCondition::BuffersAvailableCondition(
SharedBufferServer* sbs, int numBuffers) : ConditionBase(sbs),
mNumBuffers(numBuffers) {
}
bool SharedBufferServer::BuffersAvailableCondition::operator()() const {
return stack.available == mNumBuffers;
}
// ----------------------------------------------------------------------------
SharedBufferClient::QueueUpdate::QueueUpdate(SharedBufferBase* sbb)
: UpdateBase(sbb) {
}
ssize_t SharedBufferClient::QueueUpdate::operator()() {
android_atomic_inc(&stack.queued);
return NO_ERROR;
}
SharedBufferClient::DequeueUpdate::DequeueUpdate(SharedBufferBase* sbb)
: UpdateBase(sbb) {
}
ssize_t SharedBufferClient::DequeueUpdate::operator()() {
if (android_atomic_dec(&stack.available) == 0) {
LOGW("dequeue probably called from multiple threads!");
}
return NO_ERROR;
}
SharedBufferClient::CancelUpdate::CancelUpdate(SharedBufferBase* sbb,
int tail, int buf)
: UpdateBase(sbb), tail(tail), buf(buf) {
}
ssize_t SharedBufferClient::CancelUpdate::operator()() {
stack.index[tail] = buf;
android_atomic_inc(&stack.available);
return NO_ERROR;
}
SharedBufferServer::RetireUpdate::RetireUpdate(
SharedBufferBase* sbb, int numBuffers)
: UpdateBase(sbb), numBuffers(numBuffers) {
}
ssize_t SharedBufferServer::RetireUpdate::operator()() {
int32_t head = stack.head;
if (uint32_t(head) >= SharedBufferStack::NUM_BUFFER_MAX)
return BAD_VALUE;
// 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));
// lock the buffer before advancing head, which automatically unlocks
// the buffer we preventively locked upon entering this function
head = (head + 1) % numBuffers;
const int8_t headBuf = stack.index[head];
stack.headBuf = headBuf;
// head is only modified here, so we don't need to use cmpxchg
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;
}
SharedBufferServer::StatusUpdate::StatusUpdate(
SharedBufferBase* sbb, status_t status)
: UpdateBase(sbb), status(status) {
}
ssize_t SharedBufferServer::StatusUpdate::operator()() {
android_atomic_write(status, &stack.status);
return NO_ERROR;
}
// ============================================================================
SharedBufferClient::SharedBufferClient(SharedClient* sharedClient,
int surface, int num, int32_t identity)
: SharedBufferBase(sharedClient, surface, identity),
mNumBuffers(num), tail(0)
{
SharedBufferStack& stack( *mSharedStack );
tail = computeTail();
queued_head = stack.head;
}
int32_t SharedBufferClient::computeTail() const
{
SharedBufferStack& stack( *mSharedStack );
return (mNumBuffers + stack.head - stack.available + 1) % mNumBuffers;
}
ssize_t SharedBufferClient::dequeue()
{
SharedBufferStack& stack( *mSharedStack );
RWLock::AutoRLock _rd(mLock);
const nsecs_t dequeueTime = systemTime(SYSTEM_TIME_THREAD);
//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);
DequeueUpdate update(this);
updateCondition( update );
int dequeued = stack.index[tail];
tail = ((tail+1 >= mNumBuffers) ? 0 : tail+1);
LOGD_IF(DEBUG_ATOMICS, "dequeued=%d, tail++=%d, %s",
dequeued, tail, dump("").string());
mDequeueTime[dequeued] = dequeueTime;
return dequeued;
}
status_t SharedBufferClient::undoDequeue(int buf)
{
return cancel(buf);
}
status_t SharedBufferClient::cancel(int buf)
{
RWLock::AutoRLock _rd(mLock);
// calculate the new position of the tail index (essentially tail--)
int localTail = (tail + mNumBuffers - 1) % mNumBuffers;
CancelUpdate update(this, localTail, buf);
status_t err = updateCondition( update );
if (err == NO_ERROR) {
tail = localTail;
}
return err;
}
status_t SharedBufferClient::lock(int buf)
{
RWLock::AutoRLock _rd(mLock);
SharedBufferStack& stack( *mSharedStack );
LockCondition condition(this, buf);
status_t err = waitForCondition(condition);
return err;
}
status_t SharedBufferClient::queue(int buf)
{
RWLock::AutoRLock _rd(mLock);
SharedBufferStack& stack( *mSharedStack );
queued_head = (queued_head + 1) % mNumBuffers;
stack.index[queued_head] = buf;
QueueUpdate update(this);
status_t err = updateCondition( update );
LOGD_IF(DEBUG_ATOMICS, "queued=%d, %s", buf, dump("").string());
const nsecs_t now = systemTime(SYSTEM_TIME_THREAD);
stack.stats.totalTime = ns2us(now - mDequeueTime[buf]);
return err;
}
bool SharedBufferClient::needNewBuffer(int buf) const
{
SharedBufferStack& stack( *mSharedStack );
const uint32_t mask = 1<<(31-buf);
return (android_atomic_and(~mask, &stack.reallocMask) & mask) != 0;
}
status_t SharedBufferClient::setCrop(int buf, const Rect& crop)
{
SharedBufferStack& stack( *mSharedStack );
return stack.setCrop(buf, crop);
}
status_t SharedBufferClient::setTransform(int buf, uint32_t transform)
{
SharedBufferStack& stack( *mSharedStack );
return stack.setTransform(buf, uint8_t(transform));
}
status_t SharedBufferClient::setDirtyRegion(int buf, const Region& reg)
{
SharedBufferStack& stack( *mSharedStack );
return stack.setDirtyRegion(buf, reg);
}
status_t SharedBufferClient::setBufferCount(
int bufferCount, const SetBufferCountCallback& ipc)
{
SharedBufferStack& stack( *mSharedStack );
if (uint32_t(bufferCount) >= SharedBufferStack::NUM_BUFFER_MAX)
return BAD_VALUE;
if (uint32_t(bufferCount) < SharedBufferStack::NUM_BUFFER_MIN)
return BAD_VALUE;
RWLock::AutoWLock _wr(mLock);
status_t err = ipc(bufferCount);
if (err == NO_ERROR) {
mNumBuffers = bufferCount;
queued_head = (stack.head + stack.queued) % mNumBuffers;
tail = computeTail();
}
return err;
}
// ----------------------------------------------------------------------------
SharedBufferServer::SharedBufferServer(SharedClient* sharedClient,
int surface, int num, int32_t identity)
: SharedBufferBase(sharedClient, surface, identity),
mNumBuffers(num)
{
mSharedStack->init(identity);
mSharedStack->token = surface;
mSharedStack->head = num-1;
mSharedStack->available = num;
mSharedStack->queued = 0;
mSharedStack->reallocMask = 0;
memset(mSharedStack->buffers, 0, sizeof(mSharedStack->buffers));
for (int i=0 ; i<num ; i++) {
mBufferList.add(i);
mSharedStack->index[i] = i;
}
}
SharedBufferServer::~SharedBufferServer()
{
}
ssize_t SharedBufferServer::retireAndLock()
{
RWLock::AutoRLock _l(mLock);
RetireUpdate update(this, mNumBuffers);
ssize_t buf = updateCondition( update );
if (buf >= 0) {
if (uint32_t(buf) >= SharedBufferStack::NUM_BUFFER_MAX)
return BAD_VALUE;
SharedBufferStack& stack( *mSharedStack );
buf = stack.index[buf];
LOGD_IF(DEBUG_ATOMICS && buf>=0, "retire=%d, %s",
int(buf), dump("").string());
}
return buf;
}
void SharedBufferServer::setStatus(status_t status)
{
if (status < NO_ERROR) {
StatusUpdate update(this, status);
updateCondition( update );
}
}
status_t SharedBufferServer::reallocateAll()
{
RWLock::AutoRLock _l(mLock);
SharedBufferStack& stack( *mSharedStack );
uint32_t mask = mBufferList.getMask();
android_atomic_or(mask, &stack.reallocMask);
return NO_ERROR;
}
status_t SharedBufferServer::reallocateAllExcept(int buffer)
{
RWLock::AutoRLock _l(mLock);
SharedBufferStack& stack( *mSharedStack );
BufferList temp(mBufferList);
temp.remove(buffer);
uint32_t mask = temp.getMask();
android_atomic_or(mask, &stack.reallocMask);
return NO_ERROR;
}
int32_t SharedBufferServer::getQueuedCount() const
{
SharedBufferStack& stack( *mSharedStack );
return stack.queued;
}
Region SharedBufferServer::getDirtyRegion(int buf) const
{
SharedBufferStack& stack( *mSharedStack );
return stack.getDirtyRegion(buf);
}
Rect SharedBufferServer::getCrop(int buf) const
{
SharedBufferStack& stack( *mSharedStack );
return stack.getCrop(buf);
}
uint32_t SharedBufferServer::getTransform(int buf) const
{
SharedBufferStack& stack( *mSharedStack );
return stack.getTransform(buf);
}
/*
* NOTE: this is not thread-safe on the server-side, meaning
* 'head' cannot move during this operation. The client-side
* can safely operate an usual.
*
*/
status_t SharedBufferServer::resize(int newNumBuffers)
{
if ((unsigned int)(newNumBuffers) < SharedBufferStack::NUM_BUFFER_MIN ||
(unsigned int)(newNumBuffers) > SharedBufferStack::NUM_BUFFER_MAX) {
return BAD_VALUE;
}
RWLock::AutoWLock _l(mLock);
if (newNumBuffers < mNumBuffers) {
return shrink(newNumBuffers);
} else {
return grow(newNumBuffers);
}
}
status_t SharedBufferServer::grow(int newNumBuffers)
{
SharedBufferStack& stack( *mSharedStack );
const int numBuffers = mNumBuffers;
const int extra = newNumBuffers - numBuffers;
// read the head, make sure it's valid
int32_t head = stack.head;
if (uint32_t(head) >= SharedBufferStack::NUM_BUFFER_MAX)
return BAD_VALUE;
int base = numBuffers;
int32_t avail = stack.available;
int tail = head - avail + 1;
if (tail >= 0) {
int8_t* const index = const_cast<int8_t*>(stack.index);
const int nb = numBuffers - head;
memmove(&index[head + extra], &index[head], nb);
base = head;
// move head 'extra' ahead, this doesn't impact stack.index[head];
stack.head = head + extra;
}
stack.available += extra;
// fill the new free space with unused buffers
BufferList::const_iterator curr(mBufferList.free_begin());
for (int i=0 ; i<extra ; i++) {
stack.index[base+i] = *curr;
mBufferList.add(*curr);
++curr;
}
mNumBuffers = newNumBuffers;
return NO_ERROR;
}
status_t SharedBufferServer::shrink(int newNumBuffers)
{
SharedBufferStack& stack( *mSharedStack );
// Shrinking is only supported if there are no buffers currently dequeued.
int32_t avail = stack.available;
int32_t queued = stack.queued;
if (avail + queued != mNumBuffers) {
return INVALID_OPERATION;
}
// Wait for any queued buffers to be displayed.
BuffersAvailableCondition condition(this, mNumBuffers);
status_t err = waitForCondition(condition);
if (err < 0) {
return err;
}
// Reset head to index 0 and make it refer to buffer 0. The same renaming
// (head -> 0) is done in the BufferManager.
int32_t head = stack.head;
int8_t* index = const_cast<int8_t*>(stack.index);
for (int8_t i = 0; i < newNumBuffers; i++) {
index[i] = i;
}
stack.head = 0;
stack.headBuf = 0;
// Free the buffers from the end of the list that are no longer needed.
for (int i = newNumBuffers; i < mNumBuffers; i++) {
mBufferList.remove(i);
}
// Tell the client to reallocate all the buffers.
reallocateAll();
mNumBuffers = newNumBuffers;
stack.available = newNumBuffers;
return NO_ERROR;
}
SharedBufferStack::Statistics SharedBufferServer::getStats() const
{
SharedBufferStack& stack( *mSharedStack );
return stack.stats;
}
// ---------------------------------------------------------------------------
status_t SharedBufferServer::BufferList::add(int value)
{
if (uint32_t(value) >= mCapacity)
return BAD_VALUE;
uint32_t mask = 1<<(31-value);
if (mList & mask)
return ALREADY_EXISTS;
mList |= mask;
return NO_ERROR;
}
status_t SharedBufferServer::BufferList::remove(int value)
{
if (uint32_t(value) >= mCapacity)
return BAD_VALUE;
uint32_t mask = 1<<(31-value);
if (!(mList & mask))
return NAME_NOT_FOUND;
mList &= ~mask;
return NO_ERROR;
}
// ---------------------------------------------------------------------------
}; // namespace android

View File

@ -21,13 +21,15 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <utils/Errors.h>
#include <utils/threads.h>
#include <utils/CallStack.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <utils/threads.h>
#include <binder/IPCThreadState.h>
#include <binder/IMemory.h>
#include <binder/IPCThreadState.h>
#include <gui/SurfaceTextureClient.h>
#include <ui/DisplayInfo.h>
#include <ui/GraphicBuffer.h>
@ -35,12 +37,11 @@
#include <ui/GraphicLog.h>
#include <ui/Rect.h>
#include <surfaceflinger/Surface.h>
#include <surfaceflinger/ISurface.h>
#include <surfaceflinger/ISurfaceComposer.h>
#include <surfaceflinger/Surface.h>
#include <surfaceflinger/SurfaceComposerClient.h>
#include <private/surfaceflinger/SharedBufferStack.h>
#include <private/surfaceflinger/LayerState.h>
namespace android {
@ -273,58 +274,10 @@ sp<Surface> SurfaceControl::getSurface() const
// Surface
// ============================================================================
class SurfaceClient : public Singleton<SurfaceClient>
{
// all these attributes are constants
sp<ISurfaceComposer> mComposerService;
sp<ISurfaceComposerClient> mClient;
status_t mStatus;
SharedClient* mControl;
sp<IMemoryHeap> mControlMemory;
SurfaceClient()
: Singleton<SurfaceClient>(), mStatus(NO_INIT)
{
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
mComposerService = sf;
mClient = sf->createClientConnection();
if (mClient != NULL) {
mControlMemory = mClient->getControlBlock();
if (mControlMemory != NULL) {
mControl = static_cast<SharedClient *>(
mControlMemory->getBase());
if (mControl) {
mStatus = NO_ERROR;
}
}
}
}
friend class Singleton<SurfaceClient>;
public:
status_t initCheck() const {
return mStatus;
}
SharedClient* getSharedClient() const {
return mControl;
}
ssize_t getTokenForSurface(const sp<ISurface>& sur) const {
// TODO: we could cache a few tokens here to avoid an IPC
return mClient->getTokenForSurface(sur);
}
void signalServer() const {
mComposerService->signal();
}
};
ANDROID_SINGLETON_STATIC_INSTANCE(SurfaceClient);
// ---------------------------------------------------------------------------
Surface::Surface(const sp<SurfaceControl>& surface)
: mBufferMapper(GraphicBufferMapper::get()),
mClient(SurfaceClient::getInstance()),
mSharedBufferClient(NULL),
mInitCheck(NO_INIT),
: mInitCheck(NO_INIT),
mSurface(surface->mSurface),
mIdentity(surface->mIdentity),
mFormat(surface->mFormat), mFlags(surface->mFlags),
@ -334,10 +287,7 @@ Surface::Surface(const sp<SurfaceControl>& surface)
}
Surface::Surface(const Parcel& parcel, const sp<IBinder>& ref)
: mBufferMapper(GraphicBufferMapper::get()),
mClient(SurfaceClient::getInstance()),
mSharedBufferClient(NULL),
mInitCheck(NO_INIT)
: mInitCheck(NO_INIT)
{
mSurface = interface_cast<ISurface>(ref);
mIdentity = parcel.readInt32();
@ -382,7 +332,6 @@ status_t Surface::writeToParcel(
}
Mutex Surface::sCachedSurfacesLock;
DefaultKeyedVector<wp<IBinder>, wp<Surface> > Surface::sCachedSurfaces;
@ -422,32 +371,29 @@ void Surface::init()
ANativeWindow::query = query;
ANativeWindow::perform = perform;
DisplayInfo dinfo;
SurfaceComposerClient::getDisplayInfo(0, &dinfo);
const_cast<float&>(ANativeWindow::xdpi) = dinfo.xdpi;
const_cast<float&>(ANativeWindow::ydpi) = dinfo.ydpi;
// FIXME: set real values here
const_cast<int&>(ANativeWindow::minSwapInterval) = 1;
const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;
const_cast<uint32_t&>(ANativeWindow::flags) = 0;
if (mSurface != NULL) {
sp<ISurfaceTexture> surfaceTexture(mSurface->getSurfaceTexture());
LOGE_IF(surfaceTexture==0, "got a NULL ISurfaceTexture from ISurface");
if (surfaceTexture != NULL) {
mSurfaceTextureClient = new SurfaceTextureClient(surfaceTexture);
mSurfaceTextureClient->setUsage(GraphicBuffer::USAGE_HW_RENDER);
}
mNextBufferTransform = 0;
mConnected = 0;
mSwapRectangle.makeInvalid();
mNextBufferCrop = Rect(0,0);
// two buffers by default
mBuffers.setCapacity(2);
mBuffers.insertAt(0, 2);
DisplayInfo dinfo;
SurfaceComposerClient::getDisplayInfo(0, &dinfo);
const_cast<float&>(ANativeWindow::xdpi) = dinfo.xdpi;
const_cast<float&>(ANativeWindow::ydpi) = dinfo.ydpi;
if (mSurface != 0 && mClient.initCheck() == NO_ERROR) {
int32_t token = mClient.getTokenForSurface(mSurface);
if (token >= 0) {
mSharedBufferClient = new SharedBufferClient(
mClient.getSharedClient(), token, 2, mIdentity);
mInitCheck = mClient.getSharedClient()->validate(token);
} else {
LOGW("Not initializing the shared buffer client because token = %d",
token);
const_cast<int&>(ANativeWindow::minSwapInterval) =
mSurfaceTextureClient->minSwapInterval;
const_cast<int&>(ANativeWindow::maxSwapInterval) =
mSurfaceTextureClient->maxSwapInterval;
const_cast<uint32_t&>(ANativeWindow::flags) = 0;
if (mSurfaceTextureClient != 0) {
mInitCheck = NO_ERROR;
}
}
}
@ -456,9 +402,8 @@ Surface::~Surface()
{
// clear all references and trigger an IPC now, to make sure things
// happen without delay, since these resources are quite heavy.
mBuffers.clear();
mSurfaceTextureClient.clear();
mSurface.clear();
delete mSharedBufferClient;
IPCThreadState::self()->flushCommands();
}
@ -473,32 +418,6 @@ status_t Surface::validate(bool inCancelBuffer) const
LOGE("invalid token (identity=%u)", mIdentity);
return mInitCheck;
}
// verify the identity of this surface
uint32_t identity = mSharedBufferClient->getIdentity();
if (mIdentity != identity) {
LOGE("[Surface] using an invalid surface, "
"identity=%u should be %d",
mIdentity, identity);
CallStack stack;
stack.update();
stack.dump("Surface");
return BAD_INDEX;
}
// check the surface didn't become invalid
status_t err = mSharedBufferClient->getStatus();
if (err != NO_ERROR) {
if (!inCancelBuffer) {
LOGE("surface (identity=%u) is invalid, err=%d (%s)",
mIdentity, err, strerror(-err));
CallStack stack;
stack.update();
stack.dump("Surface");
}
return err;
}
return NO_ERROR;
}
@ -509,7 +428,8 @@ sp<IBinder> Surface::asBinder() const {
// ----------------------------------------------------------------------------
int Surface::setSwapInterval(ANativeWindow* window, int interval) {
return 0;
Surface* self = getSelf(window);
return self->setSwapInterval(interval);
}
int Surface::dequeueBuffer(ANativeWindow* window,
@ -554,383 +474,52 @@ int Surface::perform(ANativeWindow* window,
// ----------------------------------------------------------------------------
bool Surface::needNewBuffer(int bufIdx,
uint32_t *pWidth, uint32_t *pHeight,
uint32_t *pFormat, uint32_t *pUsage) const
{
Mutex::Autolock _l(mSurfaceLock);
// Always call needNewBuffer(), since it clears the needed buffers flags
bool needNewBuffer = mSharedBufferClient->needNewBuffer(bufIdx);
bool validBuffer = mBufferInfo.validateBuffer(mBuffers[bufIdx]);
bool newNeewBuffer = needNewBuffer || !validBuffer;
if (newNeewBuffer) {
mBufferInfo.get(pWidth, pHeight, pFormat, pUsage);
}
return newNeewBuffer;
int Surface::setSwapInterval(int interval) {
return mSurfaceTextureClient->setSwapInterval(interval);
}
int Surface::dequeueBuffer(ANativeWindowBuffer** buffer)
{
status_t err = validate();
if (err != NO_ERROR)
return err;
GraphicLog& logger(GraphicLog::getInstance());
logger.log(GraphicLog::SF_APP_DEQUEUE_BEFORE, mIdentity, -1);
ssize_t bufIdx = mSharedBufferClient->dequeue();
logger.log(GraphicLog::SF_APP_DEQUEUE_AFTER, mIdentity, bufIdx);
if (bufIdx < 0) {
LOGE("error dequeuing a buffer (%s)", strerror(bufIdx));
return bufIdx;
}
// grow the buffer array if needed
const size_t size = mBuffers.size();
const size_t needed = bufIdx+1;
if (size < needed) {
mBuffers.insertAt(size, needed-size);
}
uint32_t w, h, format, usage;
if (needNewBuffer(bufIdx, &w, &h, &format, &usage)) {
err = getBufferLocked(bufIdx, w, h, format, usage);
LOGE_IF(err, "getBufferLocked(%ld, %u, %u, %u, %08x) failed (%s)",
bufIdx, w, h, format, usage, strerror(-err));
if (err == NO_ERROR) {
// reset the width/height with the what we get from the buffer
const sp<GraphicBuffer>& backBuffer(mBuffers[bufIdx]);
mWidth = uint32_t(backBuffer->width);
mHeight = uint32_t(backBuffer->height);
}
}
// if we still don't have a buffer here, we probably ran out of memory
const sp<GraphicBuffer>& backBuffer(mBuffers[bufIdx]);
if (!err && backBuffer==0) {
err = NO_MEMORY;
}
int Surface::dequeueBuffer(ANativeWindowBuffer** buffer) {
status_t err = mSurfaceTextureClient->dequeueBuffer(buffer);
if (err == NO_ERROR) {
mDirtyRegion.set(backBuffer->width, backBuffer->height);
*buffer = backBuffer.get();
} else {
mSharedBufferClient->undoDequeue(bufIdx);
}
return err;
}
int Surface::cancelBuffer(ANativeWindowBuffer* buffer)
{
status_t err = validate(true);
switch (err) {
case NO_ERROR:
// no error, common case
break;
case BAD_INDEX:
// legitimate errors here
return err;
default:
// other errors happen because the surface is now invalid,
// for instance because it has been destroyed. In this case,
// we just fail silently (canceling a buffer is not technically
// an error at this point)
return NO_ERROR;
}
int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer));
err = mSharedBufferClient->cancel(bufIdx);
LOGE_IF(err, "error canceling buffer %d (%s)", bufIdx, strerror(-err));
return err;
}
int Surface::lockBuffer(ANativeWindowBuffer* buffer)
{
status_t err = validate();
if (err != NO_ERROR)
return err;
int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer));
GraphicLog& logger(GraphicLog::getInstance());
logger.log(GraphicLog::SF_APP_LOCK_BEFORE, mIdentity, bufIdx);
err = mSharedBufferClient->lock(bufIdx);
logger.log(GraphicLog::SF_APP_LOCK_AFTER, mIdentity, bufIdx);
LOGE_IF(err, "error locking buffer %d (%s)", bufIdx, strerror(-err));
return err;
}
int Surface::queueBuffer(ANativeWindowBuffer* buffer)
{
status_t err = validate();
if (err != NO_ERROR)
return err;
if (mSwapRectangle.isValid()) {
mDirtyRegion.set(mSwapRectangle);
}
int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer));
GraphicLog::getInstance().log(GraphicLog::SF_APP_QUEUE, mIdentity, bufIdx);
mSharedBufferClient->setTransform(bufIdx, mNextBufferTransform);
mSharedBufferClient->setCrop(bufIdx, mNextBufferCrop);
mSharedBufferClient->setDirtyRegion(bufIdx, mDirtyRegion);
err = mSharedBufferClient->queue(bufIdx);
LOGE_IF(err, "error queuing buffer %d (%s)", bufIdx, strerror(-err));
if (err == NO_ERROR) {
// TODO: can we avoid this IPC if we know there is one pending?
mClient.signalServer();
mDirtyRegion.set(buffer[0]->width, buffer[0]->height);
}
return err;
}
int Surface::query(int what, int* value) const
{
int Surface::cancelBuffer(ANativeWindowBuffer* buffer) {
return mSurfaceTextureClient->cancelBuffer(buffer);
}
int Surface::lockBuffer(ANativeWindowBuffer* buffer) {
return mSurfaceTextureClient->lockBuffer(buffer);
}
int Surface::queueBuffer(ANativeWindowBuffer* buffer) {
return mSurfaceTextureClient->queueBuffer(buffer);
}
int Surface::query(int what, int* value) const {
switch (what) {
case NATIVE_WINDOW_WIDTH:
*value = int(mWidth);
case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
// TODO: this is not needed anymore
*value = 1;
return NO_ERROR;
case NATIVE_WINDOW_HEIGHT:
*value = int(mHeight);
return NO_ERROR;
case NATIVE_WINDOW_FORMAT:
*value = int(mFormat);
return NO_ERROR;
case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
*value = MIN_UNDEQUEUED_BUFFERS;
return NO_ERROR;
case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
*value = sf->authenticateSurface(mSurface) ? 1 : 0;
return NO_ERROR;
}
case NATIVE_WINDOW_CONCRETE_TYPE:
// TODO: this is not needed anymore
*value = NATIVE_WINDOW_SURFACE;
return NO_ERROR;
}
return BAD_VALUE;
return mSurfaceTextureClient->query(what, value);
}
int Surface::perform(int operation, va_list args)
{
status_t err = validate();
if (err != NO_ERROR)
return err;
int res = NO_ERROR;
switch (operation) {
case NATIVE_WINDOW_SET_USAGE:
dispatch_setUsage( args );
break;
case NATIVE_WINDOW_CONNECT:
res = dispatch_connect( args );
break;
case NATIVE_WINDOW_DISCONNECT:
res = dispatch_disconnect( args );
break;
case NATIVE_WINDOW_SET_CROP:
res = dispatch_crop( args );
break;
case NATIVE_WINDOW_SET_BUFFER_COUNT:
res = dispatch_set_buffer_count( args );
break;
case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
res = dispatch_set_buffers_geometry( args );
break;
case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
res = dispatch_set_buffers_transform( args );
break;
case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
res = dispatch_set_buffers_timestamp( args );
break;
default:
res = NAME_NOT_FOUND;
break;
}
return res;
}
void Surface::dispatch_setUsage(va_list args) {
int usage = va_arg(args, int);
setUsage( usage );
}
int Surface::dispatch_connect(va_list args) {
int api = va_arg(args, int);
return connect( api );
}
int Surface::dispatch_disconnect(va_list args) {
int api = va_arg(args, int);
return disconnect( api );
}
int Surface::dispatch_crop(va_list args) {
android_native_rect_t const* rect = va_arg(args, android_native_rect_t*);
return crop( reinterpret_cast<Rect const*>(rect) );
}
int Surface::dispatch_set_buffer_count(va_list args) {
size_t bufferCount = va_arg(args, size_t);
return setBufferCount(bufferCount);
}
int Surface::dispatch_set_buffers_geometry(va_list args) {
int w = va_arg(args, int);
int h = va_arg(args, int);
int f = va_arg(args, int);
return setBuffersGeometry(w, h, f);
}
int Surface::dispatch_set_buffers_transform(va_list args) {
int transform = va_arg(args, int);
return setBuffersTransform(transform);
}
int Surface::dispatch_set_buffers_timestamp(va_list args) {
int64_t timestamp = va_arg(args, int64_t);
return setBuffersTimestamp(timestamp);
}
void Surface::setUsage(uint32_t reqUsage)
{
Mutex::Autolock _l(mSurfaceLock);
mBufferInfo.set(reqUsage);
}
int Surface::connect(int api)
{
Mutex::Autolock _l(mSurfaceLock);
int err = NO_ERROR;
switch (api) {
case NATIVE_WINDOW_API_EGL:
if (mConnected) {
err = -EINVAL;
} else {
mConnected = api;
}
break;
default:
err = -EINVAL;
break;
}
return err;
}
int Surface::disconnect(int api)
{
Mutex::Autolock _l(mSurfaceLock);
int err = NO_ERROR;
switch (api) {
case NATIVE_WINDOW_API_EGL:
if (mConnected == api) {
mConnected = 0;
} else {
err = -EINVAL;
}
break;
default:
err = -EINVAL;
break;
}
return err;
}
int Surface::crop(Rect const* rect)
{
Mutex::Autolock _l(mSurfaceLock);
// TODO: validate rect size
if (rect == NULL || rect->isEmpty()) {
mNextBufferCrop = Rect(0,0);
} else {
mNextBufferCrop = *rect;
}
return NO_ERROR;
}
int Surface::setBufferCount(int bufferCount)
{
sp<ISurface> s(mSurface);
if (s == 0) return NO_INIT;
class SetBufferCountIPC : public SharedBufferClient::SetBufferCountCallback {
sp<ISurface> surface;
virtual status_t operator()(int bufferCount) const {
return surface->setBufferCount(bufferCount);
}
public:
SetBufferCountIPC(const sp<ISurface>& surface) : surface(surface) { }
} ipc(s);
status_t err = mSharedBufferClient->setBufferCount(bufferCount, ipc);
LOGE_IF(err, "ISurface::setBufferCount(%d) returned %s",
bufferCount, strerror(-err));
if (err == NO_ERROR) {
// Clear out any references to the old buffers.
mBuffers.clear();
}
return err;
}
int Surface::setBuffersGeometry(int w, int h, int format)
{
if (w<0 || h<0 || format<0)
return BAD_VALUE;
if ((w && !h) || (!w && h))
return BAD_VALUE;
Mutex::Autolock _l(mSurfaceLock);
if (mConnected == NATIVE_WINDOW_API_EGL) {
return INVALID_OPERATION;
}
mBufferInfo.set(w, h, format);
if (format != 0) {
// we update the format of the surface as reported by query().
// this is to allow applications to change the format of a surface's
// buffer, and have it reflected in EGL; which is needed for
// EGLConfig validation.
mFormat = format;
}
mNextBufferCrop = Rect(0,0);
return NO_ERROR;
}
int Surface::setBuffersTransform(int transform)
{
Mutex::Autolock _l(mSurfaceLock);
mNextBufferTransform = transform;
return NO_ERROR;
}
int Surface::setBuffersTimestamp(int64_t timestamp)
{
// Surface doesn't really have anything meaningful to do with timestamps
// so they'll just be dropped here.
return NO_ERROR;
int Surface::perform(int operation, va_list args) {
return mSurfaceTextureClient->perform(operation, args);
}
// ----------------------------------------------------------------------------
int Surface::getConnectedApi() const
{
Mutex::Autolock _l(mSurfaceLock);
return mConnected;
int Surface::getConnectedApi() const {
return mSurfaceTextureClient->getConnectedApi();
}
// ----------------------------------------------------------------------------
@ -967,16 +556,17 @@ status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking)
}
// we're intending to do software rendering from this point
setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
mSurfaceTextureClient->setUsage(
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
ANativeWindowBuffer* out;
status_t err = dequeueBuffer(&out);
status_t err = mSurfaceTextureClient->dequeueBuffer(&out);
LOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
if (err == NO_ERROR) {
sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
err = lockBuffer(backBuffer.get());
LOGE_IF(err, "lockBuffer (idx=%d) failed (%s)",
getBufferIndex(backBuffer), strerror(-err));
err = mSurfaceTextureClient->lockBuffer(backBuffer.get());
LOGE_IF(err, "lockBuffer (handle=%p) failed (%s)",
backBuffer->handle, strerror(-err));
if (err == NO_ERROR) {
const Rect bounds(backBuffer->width, backBuffer->height);
const Region boundsRegion(bounds);
@ -1043,110 +633,14 @@ status_t Surface::unlockAndPost()
status_t err = mLockedBuffer->unlock();
LOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
err = queueBuffer(mLockedBuffer.get());
LOGE_IF(err, "queueBuffer (idx=%d) failed (%s)",
getBufferIndex(mLockedBuffer), strerror(-err));
err = mSurfaceTextureClient->queueBuffer(mLockedBuffer.get());
LOGE_IF(err, "queueBuffer (handle=%p) failed (%s)",
mLockedBuffer->handle, strerror(-err));
mPostedBuffer = mLockedBuffer;
mLockedBuffer = 0;
return err;
}
void Surface::setSwapRectangle(const Rect& r) {
Mutex::Autolock _l(mSurfaceLock);
mSwapRectangle = r;
}
int Surface::getBufferIndex(const sp<GraphicBuffer>& buffer) const
{
int idx = buffer->getIndex();
if (idx < 0) {
// The buffer doesn't have an index set. See if the handle the same as
// one of the buffers for which we do know the index. This can happen
// e.g. if GraphicBuffer is used to wrap an ANativeWindowBuffer that
// was dequeued from an ANativeWindow.
for (size_t i = 0; i < mBuffers.size(); i++) {
if (mBuffers[i] != 0 && buffer->handle == mBuffers[i]->handle) {
idx = mBuffers[i]->getIndex();
break;
}
}
}
return idx;
}
status_t Surface::getBufferLocked(int index,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage)
{
sp<ISurface> s(mSurface);
if (s == 0) return NO_INIT;
status_t err = NO_MEMORY;
// free the current buffer
sp<GraphicBuffer>& currentBuffer(mBuffers.editItemAt(index));
if (currentBuffer != 0) {
currentBuffer.clear();
}
sp<GraphicBuffer> buffer = s->requestBuffer(index, w, h, format, usage);
LOGE_IF(buffer==0,
"ISurface::getBuffer(%d, %08x) returned NULL",
index, usage);
if (buffer != 0) { // this should always happen by construction
LOGE_IF(buffer->handle == NULL,
"Surface (identity=%d) requestBuffer(%d, %u, %u, %u, %08x) "
"returned a buffer with a null handle",
mIdentity, index, w, h, format, usage);
err = mSharedBufferClient->getStatus();
LOGE_IF(err, "Surface (identity=%d) state = %d", mIdentity, err);
if (!err && buffer->handle != NULL) {
currentBuffer = buffer;
currentBuffer->setIndex(index);
} else {
err = err<0 ? err : status_t(NO_MEMORY);
}
}
return err;
}
// ----------------------------------------------------------------------------
Surface::BufferInfo::BufferInfo()
: mWidth(0), mHeight(0), mFormat(0),
mUsage(GRALLOC_USAGE_HW_RENDER), mDirty(0)
{
}
void Surface::BufferInfo::set(uint32_t w, uint32_t h, uint32_t format) {
if ((mWidth != w) || (mHeight != h) || (mFormat != format)) {
mWidth = w;
mHeight = h;
mFormat = format;
mDirty |= GEOMETRY;
}
}
void Surface::BufferInfo::set(uint32_t usage) {
mUsage = usage;
}
void Surface::BufferInfo::get(uint32_t *pWidth, uint32_t *pHeight,
uint32_t *pFormat, uint32_t *pUsage) const {
*pWidth = mWidth;
*pHeight = mHeight;
*pFormat = mFormat;
*pUsage = mUsage;
}
bool Surface::BufferInfo::validateBuffer(const sp<GraphicBuffer>& buffer) const {
// make sure we AT LEAST have the usage flags we want
if (mDirty || buffer==0 ||
((buffer->usage & mUsage) != mUsage)) {
mDirty = 0;
return false;
}
return true;
}
// ----------------------------------------------------------------------------
}; // namespace android

View File

@ -20,19 +20,20 @@
#include <sys/types.h>
#include <utils/Errors.h>
#include <utils/threads.h>
#include <utils/SortedVector.h>
#include <utils/Log.h>
#include <utils/Singleton.h>
#include <utils/SortedVector.h>
#include <utils/String8.h>
#include <utils/threads.h>
#include <binder/IServiceManager.h>
#include <binder/IMemory.h>
#include <binder/IServiceManager.h>
#include <ui/DisplayInfo.h>
#include <surfaceflinger/ISurface.h>
#include <surfaceflinger/ISurfaceComposer.h>
#include <surfaceflinger/ISurfaceComposerClient.h>
#include <surfaceflinger/ISurface.h>
#include <surfaceflinger/SurfaceComposerClient.h>
#include <private/surfaceflinger/LayerState.h>
@ -217,7 +218,7 @@ void SurfaceComposerClient::dispose()
status_t SurfaceComposerClient::getDisplayInfo(
DisplayID dpy, DisplayInfo* info)
{
if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX)
if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
return BAD_VALUE;
volatile surface_flinger_cblk_t const * cblk = get_cblk();
@ -235,7 +236,7 @@ status_t SurfaceComposerClient::getDisplayInfo(
ssize_t SurfaceComposerClient::getDisplayWidth(DisplayID dpy)
{
if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX)
if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
return BAD_VALUE;
volatile surface_flinger_cblk_t const * cblk = get_cblk();
volatile display_cblk_t const * dcblk = cblk->displays + dpy;
@ -244,7 +245,7 @@ ssize_t SurfaceComposerClient::getDisplayWidth(DisplayID dpy)
ssize_t SurfaceComposerClient::getDisplayHeight(DisplayID dpy)
{
if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX)
if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
return BAD_VALUE;
volatile surface_flinger_cblk_t const * cblk = get_cblk();
volatile display_cblk_t const * dcblk = cblk->displays + dpy;
@ -253,7 +254,7 @@ ssize_t SurfaceComposerClient::getDisplayHeight(DisplayID dpy)
ssize_t SurfaceComposerClient::getDisplayOrientation(DisplayID dpy)
{
if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX)
if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
return BAD_VALUE;
volatile surface_flinger_cblk_t const * cblk = get_cblk();
volatile display_cblk_t const * dcblk = cblk->displays + dpy;

View File

@ -181,6 +181,12 @@ int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer) {
int SurfaceTextureClient::query(int what, int* value) const {
LOGV("SurfaceTextureClient::query");
switch (what) {
case NATIVE_WINDOW_FORMAT:
if (mReqFormat) {
*value = mReqFormat;
return NO_ERROR;
}
break;
case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
// TODO: this is not needed anymore
*value = 0;

View File

@ -2,18 +2,18 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
clz.cpp.arm \
DisplayHardware/DisplayHardware.cpp \
Layer.cpp \
LayerBase.cpp \
LayerDim.cpp \
DisplayHardware/DisplayHardware.cpp \
DisplayHardware/DisplayHardwareBase.cpp \
DisplayHardware/HWComposer.cpp \
GLExtensions.cpp \
Layer.cpp \
LayerBase.cpp \
LayerDim.cpp \
MessageQueue.cpp \
SurfaceFlinger.cpp \
TextureManager.cpp \
Transform.cpp
DisplayHardware/HWComposer.cpp \
GLExtensions.cpp \
MessageQueue.cpp \
SurfaceFlinger.cpp \
SurfaceTextureLayer.cpp \
Transform.cpp \
LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\"
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES

File diff suppressed because it is too large Load Diff

View File

@ -20,9 +20,11 @@
#include <stdint.h>
#include <sys/types.h>
#include <gui/SurfaceTexture.h>
#include <pixelflinger/pixelflinger.h>
#include <ui/GraphicBuffer.h>
#include <ui/PixelFormat.h>
#include <pixelflinger/pixelflinger.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
@ -30,8 +32,8 @@
#include <GLES/glext.h>
#include "LayerBase.h"
#include "SurfaceTextureLayer.h"
#include "Transform.h"
#include "TextureManager.h"
namespace android {
@ -40,7 +42,6 @@ namespace android {
class FreezeLock;
class Client;
class GLExtensions;
class UserClient;
// ---------------------------------------------------------------------------
@ -58,164 +59,59 @@ public:
status_t setBuffers(uint32_t w, uint32_t h,
PixelFormat format, uint32_t flags=0);
// associate a UserClient to this Layer
status_t setToken(const sp<UserClient>& uc, SharedClient* sc, int32_t idx);
int32_t getToken() const;
sp<UserClient> getClient() const;
// Set this Layer's buffers size
void setBufferSize(uint32_t w, uint32_t h);
bool isFixedSize() const;
// LayerBase interface
virtual void setGeometry(hwc_layer_t* hwcl);
virtual void setPerFrameData(hwc_layer_t* hwcl);
virtual void drawForSreenShot() const;
virtual void onDraw(const Region& clip) const;
virtual uint32_t doTransaction(uint32_t transactionFlags);
virtual void lockPageFlip(bool& recomputeVisibleRegions);
virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
virtual bool needsBlending(const sp<GraphicBuffer>& buffer) const;
virtual bool needsBlending() const;
virtual bool isOpaque() const;
virtual bool needsDithering() const { return mNeedsDithering; }
virtual bool needsFiltering() const;
virtual bool isSecure() const { return mSecure; }
virtual bool isProtected() const;
virtual sp<Surface> createSurface() const;
virtual void onRemoved();
// only for debugging
inline sp<GraphicBuffer> getBuffer(int i) const {
return mBufferManager.getBuffer(i); }
// only for debugging
inline const sp<FreezeLock>& getFreezeLock() const {
return mFreezeLock; }
inline const sp<FreezeLock>& getFreezeLock() const { return mFreezeLock; }
protected:
virtual void destroy() const;
virtual void onFirstRef();
virtual void dump(String8& result, char* scratch, size_t size) const;
private:
void reloadTexture(const Region& dirty);
friend class SurfaceTextureLayer;
void onFrameQueued();
virtual sp<ISurface> createSurface();
uint32_t getEffectiveUsage(uint32_t usage) const;
sp<GraphicBuffer> requestBuffer(int bufferIdx,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
status_t setBufferCount(int bufferCount);
void setFixedSize(bool fixedSize);
bool isCropped() const;
static bool getOpacityForFormat(uint32_t format);
// -----------------------------------------------------------------------
class SurfaceLayer : public LayerBaseClient::Surface {
public:
SurfaceLayer(const sp<SurfaceFlinger>& flinger, const sp<Layer>& owner);
~SurfaceLayer();
private:
virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
virtual status_t setBufferCount(int bufferCount);
sp<Layer> getOwner() const {
return static_cast<Layer*>(Surface::getOwner().get());
}
};
friend class SurfaceLayer;
// -----------------------------------------------------------------------
class ClientRef {
ClientRef(const ClientRef& rhs);
ClientRef& operator = (const ClientRef& rhs);
mutable Mutex mLock;
// binder thread, page-flip thread
sp<SharedBufferServer> mControlBlock;
wp<UserClient> mUserClient;
int32_t mToken;
public:
ClientRef();
~ClientRef();
int32_t getToken() const;
sp<UserClient> getClient() const;
status_t setToken(const sp<UserClient>& uc,
const sp<SharedBufferServer>& sharedClient, int32_t token);
sp<UserClient> getUserClientUnsafe() const;
class Access {
Access(const Access& rhs);
Access& operator = (const Access& rhs);
sp<UserClient> mUserClientStrongRef;
sp<SharedBufferServer> mControlBlock;
public:
Access(const ClientRef& ref);
~Access();
inline SharedBufferServer* get() const { return mControlBlock.get(); }
};
friend class Access;
};
// -----------------------------------------------------------------------
class BufferManager {
static const size_t NUM_BUFFERS = 2;
struct BufferData {
sp<GraphicBuffer> buffer;
Image texture;
};
// this lock protect mBufferData[].buffer but since there
// is very little contention, we have only one like for
// the whole array, we also use it to protect mNumBuffers.
mutable Mutex mLock;
BufferData mBufferData[SharedBufferStack::NUM_BUFFER_MAX];
size_t mNumBuffers;
Texture mFailoverTexture;
TextureManager& mTextureManager;
ssize_t mActiveBufferIndex;
sp<GraphicBuffer> mActiveBuffer;
bool mFailover;
static status_t destroyTexture(Image* tex, EGLDisplay dpy);
public:
static size_t getDefaultBufferCount() { return NUM_BUFFERS; }
BufferManager(TextureManager& tm);
~BufferManager();
// detach/attach buffer from/to given index
sp<GraphicBuffer> detachBuffer(size_t index);
status_t attachBuffer(size_t index, const sp<GraphicBuffer>& buffer);
// resize the number of active buffers
status_t resize(size_t size, const sp<SurfaceFlinger>& flinger,
EGLDisplay dpy);
// ----------------------------------------------
// must be called from GL thread
// set/get active buffer index
status_t setActiveBufferIndex(size_t index);
size_t getActiveBufferIndex() const;
// return the active buffer
sp<GraphicBuffer> getActiveBuffer() const;
// return wether we have an active buffer
bool hasActiveBuffer() const;
// return the active texture (or fail-over)
Texture getActiveTexture() const;
// frees resources associated with all buffers
status_t destroy(EGLDisplay dpy);
// load bitmap data into the active buffer
status_t loadTexture(const Region& dirty, const GGLSurface& t);
// make active buffer an EGLImage if needed
status_t initEglImage(EGLDisplay dpy,
const sp<GraphicBuffer>& buffer);
// ----------------------------------------------
// only for debugging
sp<GraphicBuffer> getBuffer(size_t index) const;
};
// -----------------------------------------------------------------------
// constants
sp<SurfaceTextureLayer> mSurfaceTexture;
GLuint mTextureName;
// thread-safe
ClientRef mUserClientRef;
volatile int32_t mQueuedFrames;
// main thread
sp<GraphicBuffer> mActiveBuffer;
GLfloat mTextureMatrix[16];
Rect mCurrentCrop;
uint32_t mCurrentTransform;
bool mCurrentOpacity;
// constants
PixelFormat mFormat;
const GLExtensions& mGLExtensions;
bool mNeedsBlending;
bool mOpaqueLayer;
bool mNeedsDithering;
// page-flip thread (currently main thread)
@ -226,18 +122,8 @@ private:
// page-flip thread and transaction thread (currently main thread)
sp<FreezeLock> mFreezeLock;
// see threading usage in declaration
TextureManager mTextureManager;
BufferManager mBufferManager;
// binder thread, transaction thread
mutable Mutex mLock;
uint32_t mWidth;
uint32_t mHeight;
uint32_t mReqWidth;
uint32_t mReqHeight;
uint32_t mReqFormat;
bool mNeedsScaling;
bool mFixedSize;
};

View File

@ -32,8 +32,6 @@
#include "LayerBase.h"
#include "SurfaceFlinger.h"
#include "DisplayHardware/DisplayHardware.h"
#include "TextureManager.h"
namespace android {
@ -44,7 +42,7 @@ int32_t LayerBase::sSequence = 1;
LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display)
: dpy(display), contentDirty(false),
sequence(uint32_t(android_atomic_inc(&sSequence))),
mFlinger(flinger),
mFlinger(flinger), mFiltering(false),
mNeedsFiltering(false),
mOrientation(0),
mLeft(0), mTop(0),
@ -54,8 +52,6 @@ LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display)
{
const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware());
mFlags = hw.getFlags();
mBufferCrop.makeInvalid();
mBufferTransform = 0;
}
LayerBase::~LayerBase()
@ -310,6 +306,16 @@ void LayerBase::setPerFrameData(hwc_layer_t* hwcl) {
hwcl->handle = NULL;
}
void LayerBase::setFiltering(bool filtering)
{
mFiltering = filtering;
}
bool LayerBase::getFiltering() const
{
return mFiltering;
}
void LayerBase::draw(const Region& clip) const
{
// reset GL state
@ -318,10 +324,12 @@ void LayerBase::draw(const Region& clip) const
onDraw(clip);
}
void LayerBase::drawForSreenShot() const
void LayerBase::drawForSreenShot()
{
const DisplayHardware& hw(graphicPlane(0).displayHardware());
setFiltering(true);
onDraw( Region(hw.bounds()) );
setFiltering(false);
}
void LayerBase::clearWithOpenGL(const Region& clip, GLclampf red,
@ -332,8 +340,12 @@ void LayerBase::clearWithOpenGL(const Region& clip, GLclampf red,
const uint32_t fbHeight = hw.getHeight();
glColor4f(red,green,blue,alpha);
TextureManager::deactivateTextures();
#if defined(GL_OES_EGL_image_external)
if (GLExtensions::getInstance().haveTextureExternal()) {
glDisable(GL_TEXTURE_EXTERNAL_OES);
}
#endif
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
glDisable(GL_DITHER);
@ -354,24 +366,11 @@ void LayerBase::clearWithOpenGL(const Region& clip) const
clearWithOpenGL(clip,0,0,0,0);
}
template <typename T>
static inline
void swap(T& a, T& b) {
T t(a);
a = b;
b = t;
}
void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const
void LayerBase::drawWithOpenGL(const Region& clip) const
{
const DisplayHardware& hw(graphicPlane(0).displayHardware());
const uint32_t fbHeight = hw.getHeight();
const State& s(drawingState());
// bind our texture
TextureManager::activateTexture(texture, needsFiltering());
uint32_t width = texture.width;
uint32_t height = texture.height;
GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
if (UNLIKELY(s.alpha < 0xFF)) {
@ -387,7 +386,7 @@ void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const
} else {
glColor4f(1, 1, 1, 1);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
if (needsBlending()) {
if (!isOpaque()) {
glEnable(GL_BLEND);
glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
} else {
@ -395,86 +394,20 @@ void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const
}
}
/*
* compute texture coordinates
* here, we handle NPOT, cropping and buffer transformations
*/
GLfloat cl, ct, cr, cb;
if (!mBufferCrop.isEmpty()) {
// source is cropped
const GLfloat us = (texture.NPOTAdjust ? texture.wScale : 1.0f) / width;
const GLfloat vs = (texture.NPOTAdjust ? texture.hScale : 1.0f) / height;
cl = mBufferCrop.left * us;
ct = mBufferCrop.top * vs;
cr = mBufferCrop.right * us;
cb = mBufferCrop.bottom * vs;
} else {
cl = 0;
ct = 0;
cr = (texture.NPOTAdjust ? texture.wScale : 1.0f);
cb = (texture.NPOTAdjust ? texture.hScale : 1.0f);
}
/*
* For the buffer transformation, we apply the rotation last.
* Since we're transforming the texture-coordinates, we need
* to apply the inverse of the buffer transformation:
* inverse( FLIP_V -> FLIP_H -> ROT_90 )
* <=> inverse( ROT_90 * FLIP_H * FLIP_V )
* = inverse(FLIP_V) * inverse(FLIP_H) * inverse(ROT_90)
* = FLIP_V * FLIP_H * ROT_270
* <=> ROT_270 -> FLIP_H -> FLIP_V
*
* The rotation is performed first, in the texture coordinate space.
*
*/
struct TexCoords {
GLfloat u;
GLfloat v;
};
enum {
// name of the corners in the texture map
LB = 0, // left-bottom
LT = 1, // left-top
RT = 2, // right-top
RB = 3 // right-bottom
};
// vertices in screen space
int vLT = LB;
int vLB = LT;
int vRB = RT;
int vRT = RB;
// the texture's source is rotated
uint32_t transform = mBufferTransform;
if (transform & HAL_TRANSFORM_ROT_90) {
vLT = RB;
vLB = LB;
vRB = LT;
vRT = RT;
}
if (transform & HAL_TRANSFORM_FLIP_V) {
swap(vLT, vLB);
swap(vRT, vRB);
}
if (transform & HAL_TRANSFORM_FLIP_H) {
swap(vLT, vRT);
swap(vLB, vRB);
}
TexCoords texCoords[4];
texCoords[vLT].u = cl;
texCoords[vLT].v = ct;
texCoords[vLB].u = cl;
texCoords[vLB].v = cb;
texCoords[vRB].u = cr;
texCoords[vRB].v = cb;
texCoords[vRT].u = cr;
texCoords[vRT].v = ct;
texCoords[0].u = 0;
texCoords[0].v = 1;
texCoords[1].u = 0;
texCoords[1].v = 0;
texCoords[2].u = 1;
texCoords[2].v = 0;
texCoords[3].u = 1;
texCoords[3].v = 1;
if (needsDithering()) {
glEnable(GL_DITHER);
@ -497,20 +430,6 @@ void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
void LayerBase::setBufferCrop(const Rect& crop) {
if (mBufferCrop != crop) {
mBufferCrop = crop;
mFlinger->invalidateHwcGeometry();
}
}
void LayerBase::setBufferTransform(uint32_t transform) {
if (mBufferTransform != transform) {
mBufferTransform = transform;
mFlinger->invalidateHwcGeometry();
}
}
void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const
{
const Layer::State& s(drawingState());
@ -518,10 +437,10 @@ void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const
"+ %s %p\n"
" "
"z=%9d, pos=(%4d,%4d), size=(%4d,%4d), "
"needsBlending=%1d, needsDithering=%1d, invalidate=%1d, "
"isOpaque=%1d, needsDithering=%1d, invalidate=%1d, "
"alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n",
getTypeId(), this, s.z, tx(), ty(), s.w, s.h,
needsBlending(), needsDithering(), contentDirty,
isOpaque(), needsDithering(), contentDirty,
s.alpha, s.flags,
s.transform[0][0], s.transform[0][1],
s.transform[1][0], s.transform[1][1]);
@ -555,9 +474,22 @@ LayerBaseClient::~LayerBaseClient()
}
}
sp<LayerBaseClient::Surface> LayerBaseClient::getSurface()
sp<ISurface> LayerBaseClient::createSurface()
{
sp<Surface> s;
class BSurface : public BnSurface, public LayerCleaner {
virtual sp<ISurfaceTexture> getSurfaceTexture() const { return 0; }
public:
BSurface(const sp<SurfaceFlinger>& flinger,
const sp<LayerBaseClient>& layer)
: LayerCleaner(flinger, layer) { }
};
sp<ISurface> sur(new BSurface(mFlinger, this));
return sur;
}
sp<ISurface> LayerBaseClient::getSurface()
{
sp<ISurface> s;
Mutex::Autolock _l(mLock);
LOG_ALWAYS_FATAL_IF(mHasSurface,
@ -573,12 +505,6 @@ wp<IBinder> LayerBaseClient::getSurfaceBinder() const {
return mClientSurfaceBinder;
}
sp<LayerBaseClient::Surface> LayerBaseClient::createSurface() const
{
return new Surface(mFlinger, mIdentity,
const_cast<LayerBaseClient *>(this));
}
void LayerBaseClient::dump(String8& result, char* buffer, size_t SIZE) const
{
LayerBase::dump(result, buffer, SIZE);
@ -601,44 +527,14 @@ void LayerBaseClient::shortDump(String8& result, char* scratch, size_t size) con
// ---------------------------------------------------------------------------
LayerBaseClient::Surface::Surface(
const sp<SurfaceFlinger>& flinger,
int identity,
const sp<LayerBaseClient>& owner)
: mFlinger(flinger), mIdentity(identity), mOwner(owner)
{
LayerBaseClient::LayerCleaner::LayerCleaner(const sp<SurfaceFlinger>& flinger,
const sp<LayerBaseClient>& layer)
: mFlinger(flinger), mLayer(layer) {
}
LayerBaseClient::Surface::~Surface()
{
/*
* This is a good place to clean-up all client resources
*/
LayerBaseClient::LayerCleaner::~LayerCleaner() {
// destroy client resources
mFlinger->destroySurface(mOwner);
}
sp<LayerBaseClient> LayerBaseClient::Surface::getOwner() const {
sp<LayerBaseClient> owner(mOwner.promote());
return owner;
}
status_t LayerBaseClient::Surface::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
return BnSurface::onTransact(code, data, reply, flags);
}
sp<GraphicBuffer> LayerBaseClient::Surface::requestBuffer(int bufferIdx,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage)
{
return NULL;
}
status_t LayerBaseClient::Surface::setBufferCount(int bufferCount)
{
return INVALID_OPERATION;
mFlinger->destroySurface(mLayer);
}
// ---------------------------------------------------------------------------

View File

@ -29,7 +29,6 @@
#include <ui/Region.h>
#include <surfaceflinger/ISurfaceComposerClient.h>
#include <private/surfaceflinger/SharedBufferStack.h>
#include <private/surfaceflinger/LayerState.h>
#include <pixelflinger/pixelflinger.h>
@ -43,13 +42,12 @@ namespace android {
// ---------------------------------------------------------------------------
class DisplayHardware;
class Client;
class DisplayHardware;
class GraphicBuffer;
class GraphicPlane;
class LayerBaseClient;
class SurfaceFlinger;
class Texture;
// ---------------------------------------------------------------------------
@ -121,7 +119,7 @@ public:
* to perform the actual drawing.
*/
virtual void draw(const Region& clip) const;
virtual void drawForSreenShot() const;
virtual void drawForSreenShot();
/**
* onDraw - draws the surface.
@ -174,9 +172,9 @@ public:
virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
/**
* needsBlending - true if this surface needs blending
* isOpaque - true if this surface is opaque
*/
virtual bool needsBlending() const { return false; }
virtual bool isOpaque() const { return true; }
/**
* needsDithering - true if this surface needs dithering
@ -184,11 +182,9 @@ public:
virtual bool needsDithering() const { return false; }
/**
* needsLinearFiltering - true if this surface needs filtering
* needsLinearFiltering - true if this surface's state requires filtering
*/
virtual bool needsFiltering() const {
return (!(mFlags & DisplayHardware::SLOW_CONFIG)) && mNeedsFiltering;
}
virtual bool needsFiltering() const { return mNeedsFiltering; }
/**
* isSecure - true if this surface is secure, that is if it prevents
@ -231,21 +227,25 @@ protected:
void clearWithOpenGL(const Region& clip, GLclampf r, GLclampf g,
GLclampf b, GLclampf alpha) const;
void clearWithOpenGL(const Region& clip) const;
void drawWithOpenGL(const Region& clip, const Texture& texture) const;
// these must be called from the post/drawing thread
void setBufferCrop(const Rect& crop);
void setBufferTransform(uint32_t transform);
void drawWithOpenGL(const Region& clip) const;
void setFiltering(bool filtering);
bool getFiltering() const;
sp<SurfaceFlinger> mFlinger;
uint32_t mFlags;
// post/drawing thread
Rect mBufferCrop;
uint32_t mBufferTransform;
private:
// accessed only in the main thread
// Whether filtering is forced on or not
bool mFiltering;
// cached during validateVisibility()
// Whether filtering is needed b/c of the drawingstate
bool mNeedsFiltering;
protected:
// cached during validateVisibility()
int32_t mOrientation;
GLfloat mVertices[4][2];
Rect mTransformedBounds;
@ -281,52 +281,38 @@ private:
class LayerBaseClient : public LayerBase
{
public:
class Surface;
LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
const sp<Client>& client);
virtual ~LayerBaseClient();
sp<Surface> getSurface();
virtual ~LayerBaseClient();
sp<ISurface> getSurface();
wp<IBinder> getSurfaceBinder() const;
virtual sp<Surface> createSurface() const;
virtual sp<LayerBaseClient> getLayerBaseClient() const {
return const_cast<LayerBaseClient*>(this); }
virtual const char* getTypeId() const { return "LayerBaseClient"; }
uint32_t getIdentity() const { return mIdentity; }
class Surface : public BnSurface {
public:
int32_t getIdentity() const { return mIdentity; }
protected:
Surface(const sp<SurfaceFlinger>& flinger, int identity,
const sp<LayerBaseClient>& owner);
virtual ~Surface();
virtual status_t onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags);
sp<LayerBaseClient> getOwner() const;
private:
virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
virtual status_t setBufferCount(int bufferCount);
protected:
friend class LayerBaseClient;
sp<SurfaceFlinger> mFlinger;
int32_t mIdentity;
wp<LayerBaseClient> mOwner;
};
friend class Surface;
protected:
virtual void dump(String8& result, char* scratch, size_t size) const;
virtual void shortDump(String8& result, char* scratch, size_t size) const;
class LayerCleaner {
sp<SurfaceFlinger> mFlinger;
wp<LayerBaseClient> mLayer;
protected:
~LayerCleaner();
public:
LayerCleaner(const sp<SurfaceFlinger>& flinger,
const sp<LayerBaseClient>& layer);
};
private:
virtual sp<ISurface> createSurface();
mutable Mutex mLock;
mutable bool mHasSurface;
wp<IBinder> mClientSurfaceBinder;

View File

@ -65,8 +65,6 @@ void LayerDim::onDraw(const Region& clip) const
glDisable(GL_TEXTURE_EXTERNAL_OES);
}
#endif
glDisable(GL_TEXTURE_2D);
glVertexPointer(2, GL_FLOAT, 0, mVertices);
while (it != end) {

View File

@ -37,7 +37,7 @@ public:
virtual ~LayerDim();
virtual void onDraw(const Region& clip) const;
virtual bool needsBlending() const { return true; }
virtual bool isOpaque() const { return false; }
virtual bool isSecure() const { return false; }
virtual bool isProtectedByApp() const { return false; }
virtual bool isProtectedByDRM() const { return false; }

View File

@ -53,6 +53,8 @@
#include "DisplayHardware/DisplayHardware.h"
#include "DisplayHardware/HWComposer.h"
#include <private/surfaceflinger/SharedBufferStack.h>
/* ideally AID_GRAPHICS would be in a semi-public header
* or there would be a way to map a user/group name to its id
*/
@ -133,17 +135,6 @@ sp<ISurfaceComposerClient> SurfaceFlinger::createConnection()
return bclient;
}
sp<ISurfaceComposerClient> SurfaceFlinger::createClientConnection()
{
sp<ISurfaceComposerClient> bclient;
sp<UserClient> client(new UserClient(this));
status_t err = client->initCheck();
if (err == NO_ERROR) {
bclient = client;
}
return bclient;
}
sp<IGraphicBufferAlloc> SurfaceFlinger::createGraphicBufferAlloc()
{
sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc());
@ -322,11 +313,6 @@ void SurfaceFlinger::signalEvent() {
mEventQueue.invalidate();
}
void SurfaceFlinger::signal() const {
// this is the IPC call
const_cast<SurfaceFlinger*>(this)->signalEvent();
}
bool SurfaceFlinger::authenticateSurface(const sp<ISurface>& surface) const {
Mutex::Autolock _l(mStateLock);
sp<IBinder> surfBinder(surface->asBinder());
@ -658,7 +644,7 @@ void SurfaceFlinger::computeVisibleRegions(
// handle hidden surfaces by setting the visible region to empty
if (LIKELY(!(s.flags & ISurfaceComposer::eLayerHidden) && s.alpha)) {
const bool translucent = layer->needsBlending();
const bool translucent = !layer->isOpaque();
const Rect bounds(layer->visibleBounds());
visibleRegion.set(bounds);
visibleRegion.andSelf(screenRegion);
@ -921,7 +907,7 @@ void SurfaceFlinger::composeSurfaces(const Region& dirty)
for (size_t i=0 ; i<count ; i++) {
if (cur[i].hints & HWC_HINT_CLEAR_FB) {
const sp<LayerBase>& layer(layers[i]);
if (!(layer->needsBlending())) {
if (layer->isOpaque()) {
transparent.orSelf(layer->visibleRegionScreen);
}
}
@ -979,8 +965,6 @@ void SurfaceFlinger::debugFlashRegions()
composeSurfaces(repaint);
}
TextureManager::deactivateTextures();
glDisable(GL_BLEND);
glDisable(GL_DITHER);
glDisable(GL_SCISSOR_TEST);
@ -1070,6 +1054,7 @@ void SurfaceFlinger::drawWormhole() const
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_2D);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
}
@ -1269,7 +1254,7 @@ sp<ISurface> SurfaceFlinger::createSurface(
uint32_t flags)
{
sp<LayerBaseClient> layer;
sp<LayerBaseClient::Surface> surfaceHandle;
sp<ISurface> surfaceHandle;
if (int32_t(w|h) < 0) {
LOGE("createSurface() failed, w or h is negative (w=%d, h=%d)",
@ -1300,13 +1285,13 @@ sp<ISurface> SurfaceFlinger::createSurface(
surfaceHandle = layer->getSurface();
if (surfaceHandle != 0) {
params->token = token;
params->identity = surfaceHandle->getIdentity();
params->identity = layer->getIdentity();
params->width = w;
params->height = h;
params->format = format;
if (normalLayer != 0) {
Mutex::Autolock _l(mStateLock);
mLayerMap.add(surfaceHandle->asBinder(), normalLayer);
mLayerMap.add(layer->getSurfaceBinder(), normalLayer);
}
}
@ -1782,7 +1767,6 @@ status_t SurfaceFlinger::electronBeamOffAnimationImplLocked()
GLfloat vtx[8];
const GLfloat texCoords[4][2] = { {0,v}, {0,0}, {u,0}, {u,v} };
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tname);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@ -1900,6 +1884,7 @@ status_t SurfaceFlinger::electronBeamOffAnimationImplLocked()
glEnable(GL_SCISSOR_TEST);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDeleteTextures(1, &tname);
glDisable(GL_TEXTURE_2D);
return NO_ERROR;
}
@ -1930,7 +1915,6 @@ status_t SurfaceFlinger::electronBeamOnAnimationImplLocked()
GLfloat vtx[8];
const GLfloat texCoords[4][2] = { {0,v}, {0,0}, {u,0}, {u,v} };
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tname);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@ -2044,6 +2028,7 @@ status_t SurfaceFlinger::electronBeamOnAnimationImplLocked()
glEnable(GL_SCISSOR_TEST);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDeleteTextures(1, &tname);
glDisable(GL_TEXTURE_2D);
return NO_ERROR;
}
@ -2408,20 +2393,72 @@ sp<LayerBaseClient> Client::getLayerUser(int32_t i) const
return lbc;
}
sp<IMemoryHeap> Client::getControlBlock() const {
return 0;
}
ssize_t Client::getTokenForSurface(const sp<ISurface>& sur) const {
return -1;
status_t Client::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
// these must be checked
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
const int uid = ipc->getCallingUid();
const int self_pid = getpid();
if (UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != 0)) {
// we're called from a different process, do the real check
if (!checkCallingPermission(
String16("android.permission.ACCESS_SURFACE_FLINGER")))
{
LOGE("Permission Denial: "
"can't openGlobalTransaction pid=%d, uid=%d", pid, uid);
return PERMISSION_DENIED;
}
}
return BnSurfaceComposerClient::onTransact(code, data, reply, flags);
}
sp<ISurface> Client::createSurface(
ISurfaceComposerClient::surface_data_t* params,
const String8& name,
DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
uint32_t flags)
{
return mFlinger->createSurface(params, name, this,
display, w, h, format, flags);
/*
* createSurface must be called from the GL thread so that it can
* have access to the GL context.
*/
class MessageCreateSurface : public MessageBase {
sp<ISurface> result;
SurfaceFlinger* flinger;
ISurfaceComposerClient::surface_data_t* params;
Client* client;
const String8& name;
DisplayID display;
uint32_t w, h;
PixelFormat format;
uint32_t flags;
public:
MessageCreateSurface(SurfaceFlinger* flinger,
ISurfaceComposerClient::surface_data_t* params,
const String8& name, Client* client,
DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
uint32_t flags)
: flinger(flinger), params(params), client(client), name(name),
display(display), w(w), h(h), format(format), flags(flags)
{
}
sp<ISurface> getResult() const { return result; }
virtual bool handler() {
result = flinger->createSurface(params, name, client,
display, w, h, format, flags);
return true;
}
};
sp<MessageBase> msg = new MessageCreateSurface(mFlinger.get(),
params, name, this, display, w, h, format, flags);
mFlinger->postMessageSync(msg);
return static_cast<MessageCreateSurface*>( msg.get() )->getResult();
}
status_t Client::destroySurface(SurfaceID sid) {
return mFlinger->removeSurface(this, sid);
@ -2432,113 +2469,6 @@ status_t Client::setState(int32_t count, const layer_state_t* states) {
// ---------------------------------------------------------------------------
UserClient::UserClient(const sp<SurfaceFlinger>& flinger)
: ctrlblk(0), mBitmap(0), mFlinger(flinger)
{
const int pgsize = getpagesize();
const int cblksize = ((sizeof(SharedClient)+(pgsize-1))&~(pgsize-1));
mCblkHeap = new MemoryHeapBase(cblksize, 0,
"SurfaceFlinger Client control-block");
ctrlblk = static_cast<SharedClient *>(mCblkHeap->getBase());
if (ctrlblk) { // construct the shared structure in-place.
new(ctrlblk) SharedClient;
}
}
UserClient::~UserClient()
{
if (ctrlblk) {
ctrlblk->~SharedClient(); // destroy our shared-structure.
}
/*
* When a UserClient dies, it's unclear what to do exactly.
* We could go ahead and destroy all surfaces linked to that client
* however, it wouldn't be fair to the main Client
* (usually the the window-manager), which might want to re-target
* the layer to another UserClient.
* I think the best is to do nothing, or not much; in most cases the
* WM itself will go ahead and clean things up when it detects a client of
* his has died.
* The remaining question is what to display? currently we keep
* just keep the current buffer.
*/
}
status_t UserClient::initCheck() const {
return ctrlblk == 0 ? NO_INIT : NO_ERROR;
}
void UserClient::detachLayer(const Layer* layer)
{
int32_t name = layer->getToken();
if (name >= 0) {
int32_t mask = 1LU<<name;
if ((android_atomic_and(~mask, &mBitmap) & mask) == 0) {
LOGW("token %d wasn't marked as used %08x", name, int(mBitmap));
}
}
}
sp<IMemoryHeap> UserClient::getControlBlock() const {
return mCblkHeap;
}
ssize_t UserClient::getTokenForSurface(const sp<ISurface>& sur) const
{
int32_t name = NAME_NOT_FOUND;
sp<Layer> layer(mFlinger->getLayer(sur));
if (layer == 0) {
return name;
}
// if this layer already has a token, just return it
name = layer->getToken();
if ((name >= 0) && (layer->getClient() == this)) {
return name;
}
name = 0;
do {
int32_t mask = 1LU<<name;
if ((android_atomic_or(mask, &mBitmap) & mask) == 0) {
// we found and locked that name
status_t err = layer->setToken(
const_cast<UserClient*>(this), ctrlblk, name);
if (err != NO_ERROR) {
// free the name
android_atomic_and(~mask, &mBitmap);
name = err;
}
break;
}
if (++name >= int32_t(SharedBufferStack::NUM_LAYERS_MAX))
name = NO_MEMORY;
} while(name >= 0);
//LOGD("getTokenForSurface(%p) => %d (client=%p, bitmap=%08lx)",
// sur->asBinder().get(), name, this, mBitmap);
return name;
}
sp<ISurface> UserClient::createSurface(
ISurfaceComposerClient::surface_data_t* params,
const String8& name,
DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
uint32_t flags) {
return 0;
}
status_t UserClient::destroySurface(SurfaceID sid) {
return INVALID_OPERATION;
}
status_t UserClient::setState(int32_t count, const layer_state_t* states) {
return INVALID_OPERATION;
}
// ---------------------------------------------------------------------------
GraphicBufferAlloc::GraphicBufferAlloc() {}
GraphicBufferAlloc::~GraphicBufferAlloc() {}
@ -2547,11 +2477,11 @@ sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h
PixelFormat format, uint32_t usage) {
sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage));
status_t err = graphicBuffer->initCheck();
if (err != 0) {
LOGE("createGraphicBuffer: init check failed: %d", err);
return 0;
} else if (graphicBuffer->handle == 0) {
LOGE("createGraphicBuffer: unable to create GraphicBuffer");
if (err != 0 || graphicBuffer->handle == 0) {
GraphicBuffer::dumpAllocationsToSystemLog();
LOGE("GraphicBufferAlloc::createGraphicBuffer(w=%d, h=%d) "
"failed (%s), handle=%p",
w, h, strerror(-err), graphicBuffer->handle);
return 0;
}
return graphicBuffer;

View File

@ -50,6 +50,7 @@ class DisplayHardware;
class FreezeLock;
class Layer;
class LayerDim;
struct surface_flinger_cblk_t;
#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
@ -72,14 +73,14 @@ public:
private:
// ISurfaceComposerClient interface
virtual sp<IMemoryHeap> getControlBlock() const;
virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const;
virtual sp<ISurface> createSurface(
surface_data_t* params, const String8& name,
DisplayID display, uint32_t w, uint32_t h,PixelFormat format,
uint32_t flags);
virtual status_t destroySurface(SurfaceID surfaceId);
virtual status_t setState(int32_t count, const layer_state_t* states);
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
// constant
sp<SurfaceFlinger> mFlinger;
@ -92,40 +93,6 @@ private:
mutable Mutex mLock;
};
class UserClient : public BnSurfaceComposerClient
{
public:
// pointer to this client's control block
SharedClient* ctrlblk;
public:
UserClient(const sp<SurfaceFlinger>& flinger);
~UserClient();
status_t initCheck() const;
// protected by SurfaceFlinger::mStateLock
void detachLayer(const Layer* layer);
private:
// ISurfaceComposerClient interface
virtual sp<IMemoryHeap> getControlBlock() const;
virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const;
virtual sp<ISurface> createSurface(
surface_data_t* params, const String8& name,
DisplayID display, uint32_t w, uint32_t h,PixelFormat format,
uint32_t flags);
virtual status_t destroySurface(SurfaceID surfaceId);
virtual status_t setState(int32_t count, const layer_state_t* states);
// atomic-ops
mutable volatile int32_t mBitmap;
sp<IMemoryHeap> mCblkHeap;
sp<SurfaceFlinger> mFlinger;
};
class GraphicBufferAlloc : public BnGraphicBufferAlloc
{
public:
@ -199,7 +166,6 @@ public:
// ISurfaceComposer interface
virtual sp<ISurfaceComposerClient> createConnection();
virtual sp<ISurfaceComposerClient> createClientConnection();
virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc();
virtual sp<IMemoryHeap> getCblk() const;
virtual void bootFinished();
@ -208,7 +174,6 @@ public:
virtual status_t freezeDisplay(DisplayID dpy, uint32_t flags);
virtual status_t unfreezeDisplay(DisplayID dpy, uint32_t flags);
virtual int setOrientation(DisplayID dpy, int orientation, uint32_t flags);
virtual void signal() const;
virtual bool authenticateSurface(const sp<ISurface>& surface) const;
virtual status_t captureScreen(DisplayID dpy,
@ -235,7 +200,6 @@ private:
friend class Client;
friend class LayerBase;
friend class LayerBaseClient;
friend class LayerBaseClient::Surface;
friend class Layer;
friend class LayerDim;

View File

@ -0,0 +1,76 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <utils/Errors.h>
#include "Layer.h"
#include "SurfaceTextureLayer.h"
namespace android {
// ---------------------------------------------------------------------------
SurfaceTextureLayer::SurfaceTextureLayer(GLuint tex, const sp<Layer>& layer)
: SurfaceTexture(tex), mLayer(layer) {
}
SurfaceTextureLayer::~SurfaceTextureLayer() {
}
status_t SurfaceTextureLayer::setDefaultBufferSize(uint32_t w, uint32_t h)
{
//LOGD("%s, w=%u, h=%u", __PRETTY_FUNCTION__, w, h);
return SurfaceTexture::setDefaultBufferSize(w, h);
}
status_t SurfaceTextureLayer::setDefaultBufferFormat(uint32_t format)
{
mDefaultFormat = format;
return NO_ERROR;
}
status_t SurfaceTextureLayer::setBufferCount(int bufferCount) {
status_t res = SurfaceTexture::setBufferCount(bufferCount);
return res;
}
status_t SurfaceTextureLayer::dequeueBuffer(int *buf,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
status_t res(NO_INIT);
sp<Layer> layer(mLayer.promote());
if (layer != NULL) {
if (format == 0)
format = mDefaultFormat;
uint32_t effectiveUsage = layer->getEffectiveUsage(usage);
//LOGD("%s, w=%u, h=%u, format=%u, usage=%08x, effectiveUsage=%08x",
// __PRETTY_FUNCTION__, w, h, format, usage, effectiveUsage);
res = SurfaceTexture::dequeueBuffer(buf, w, h, format, effectiveUsage);
if (res == NO_ERROR) {
layer->setFixedSize(w && h);
}
}
return res;
}
// ---------------------------------------------------------------------------
}; // namespace android

View File

@ -0,0 +1,55 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_SURFACE_TEXTURE_LAYER_H
#define ANDROID_SURFACE_TEXTURE_LAYER_H
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <utils/Errors.h>
#include <gui/SurfaceTexture.h>
namespace android {
// ---------------------------------------------------------------------------
class Layer;
class SurfaceTextureLayer : public SurfaceTexture
{
wp<Layer> mLayer;
uint32_t mDefaultFormat;
public:
SurfaceTextureLayer(GLuint tex, const sp<Layer>& layer);
~SurfaceTextureLayer();
status_t setDefaultBufferSize(uint32_t w, uint32_t h);
status_t setDefaultBufferFormat(uint32_t format);
public:
virtual status_t setBufferCount(int bufferCount);
protected:
virtual status_t dequeueBuffer(int *buf, uint32_t w, uint32_t h,
uint32_t format, uint32_t usage);
};
// ---------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_SURFACE_TEXTURE_LAYER_H

View File

@ -20,18 +20,10 @@
namespace android {
int clz_impl(int32_t x);
int inline clz(int32_t x)
{
#if defined(__arm__) && !defined(__thumb__)
int inline clz(int32_t x) {
return __builtin_clz(x);
#else
return clz_impl(x);
#endif
}
}; // namespace android
#endif /* ANDROID_SURFACE_FLINGER_CLZ_H */