move lock/unlock implementaion outside of Surface into SurfaceTextureClient

This makes ANativeWindow_lock/ANativeWindow_unlockAndPost work
with ANativeWindows implemented by Surface and SurfaceTextureClient.

Also, Surface now inherits directly from SurfaceTextureClient.

Bug: 5003724
Change-Id: I9f285877c7bae9a262e9a7af91c2bae78804b2ef
This commit is contained in:
Mathias Agopian 2011-07-13 17:39:11 -07:00
parent 9c8b60dad3
commit 8f9dbf9e13
6 changed files with 308 additions and 392 deletions

View File

@ -21,6 +21,7 @@
#include <gui/SurfaceTexture.h>
#include <ui/egl/android_natives.h>
#include <ui/Region.h>
#include <utils/RefBase.h>
#include <utils/threads.h>
@ -37,29 +38,24 @@ public:
sp<ISurfaceTexture> getISurfaceTexture() const;
private:
friend class Surface;
protected:
SurfaceTextureClient();
void setISurfaceTexture(const sp<ISurfaceTexture>& surfaceTexture);
private:
// can't be copied
SurfaceTextureClient& operator = (const SurfaceTextureClient& rhs);
SurfaceTextureClient(const SurfaceTextureClient& rhs);
void init();
// ANativeWindow hooks
static int cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
static int dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
static int lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
static int perform(ANativeWindow* window, int operation, ...);
static int query(const ANativeWindow* window, int what, int* value);
static int queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
static int setSwapInterval(ANativeWindow* window, int interval);
int cancelBuffer(ANativeWindowBuffer* buffer);
int dequeueBuffer(ANativeWindowBuffer** buffer);
int lockBuffer(ANativeWindowBuffer* buffer);
int perform(int operation, va_list args);
int query(int what, int* value) const;
int queueBuffer(ANativeWindowBuffer* buffer);
int setSwapInterval(int interval);
static int hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
static int hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
static int hook_lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
static int hook_perform(ANativeWindow* window, int operation, ...);
static int hook_query(const ANativeWindow* window, int what, int* value);
static int hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
static int hook_setSwapInterval(ANativeWindow* window, int interval);
int dispatchConnect(va_list args);
int dispatchDisconnect(va_list args);
@ -71,26 +67,38 @@ private:
int dispatchSetBuffersTimestamp(va_list args);
int dispatchSetCrop(va_list args);
int dispatchSetUsage(va_list args);
int dispatchLock(va_list args);
int dispatchUnlockAndPost(va_list args);
int connect(int api);
int disconnect(int api);
int setBufferCount(int bufferCount);
int setBuffersDimensions(int w, int h);
int setBuffersFormat(int format);
int setBuffersTransform(int transform);
int setBuffersTimestamp(int64_t timestamp);
int setCrop(Rect const* rect);
int setUsage(uint32_t reqUsage);
protected:
virtual int cancelBuffer(ANativeWindowBuffer* buffer);
virtual int dequeueBuffer(ANativeWindowBuffer** buffer);
virtual int lockBuffer(ANativeWindowBuffer* buffer);
virtual int perform(int operation, va_list args);
virtual int query(int what, int* value) const;
virtual int queueBuffer(ANativeWindowBuffer* buffer);
virtual int setSwapInterval(int interval);
void freeAllBuffers();
int getSlotFromBufferLocked(android_native_buffer_t* buffer) const;
int getConnectedApi() const;
virtual int connect(int api);
virtual int disconnect(int api);
virtual int setBufferCount(int bufferCount);
virtual int setBuffersDimensions(int w, int h);
virtual int setBuffersFormat(int format);
virtual int setBuffersTransform(int transform);
virtual int setBuffersTimestamp(int64_t timestamp);
virtual int setCrop(Rect const* rect);
virtual int setUsage(uint32_t reqUsage);
virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds);
virtual int unlockAndPost();
enum { MIN_UNDEQUEUED_BUFFERS = SurfaceTexture::MIN_UNDEQUEUED_BUFFERS };
enum { NUM_BUFFER_SLOTS = SurfaceTexture::NUM_BUFFER_SLOTS };
enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
private:
void freeAllBuffers();
int getSlotFromBufferLocked(android_native_buffer_t* buffer) const;
// mSurfaceTexture is the interface to the surface texture server. All
// operations on the surface texture client ultimately translate into
// interactions with the server using this interface.
@ -145,6 +153,12 @@ private:
// variables of SurfaceTexture objects. It must be locked whenever the
// member variables are accessed.
mutable Mutex mMutex;
// must be used from the lock/unlock thread
sp<GraphicBuffer> mLockedBuffer;
sp<GraphicBuffer> mPostedBuffer;
mutable Region mOldDirtyRegion;
bool mConnectedToCpu;
};
}; // namespace android

View File

@ -28,6 +28,8 @@
#include <ui/Region.h>
#include <ui/egl/android_natives.h>
#include <gui/SurfaceTextureClient.h>
#include <surfaceflinger/ISurface.h>
#include <surfaceflinger/ISurfaceComposerClient.h>
@ -37,14 +39,9 @@ namespace android {
// ---------------------------------------------------------------------------
class GraphicBuffer;
class GraphicBufferMapper;
class IOMX;
class ISurfaceTexture;
class Rect;
class Surface;
class SurfaceComposerClient;
class SurfaceTextureClient;
// ---------------------------------------------------------------------------
@ -129,8 +126,7 @@ private:
// ---------------------------------------------------------------------------
class Surface
: public EGLNativeBase<ANativeWindow, Surface, RefBase>
class Surface : public SurfaceTextureClient
{
public:
struct SurfaceInfo {
@ -158,32 +154,14 @@ public:
sp<ISurfaceTexture> getSurfaceTexture();
// the lock/unlock APIs must be used from the same thread
status_t lock(SurfaceInfo* info, bool blocking = true);
status_t lock(SurfaceInfo* info, Region* dirty, bool blocking = true);
status_t lock(SurfaceInfo* info, Region* dirty = NULL);
status_t unlockAndPost();
sp<IBinder> asBinder() const;
private:
/*
* Android frameworks friends
* (eventually this should go away and be replaced by proper APIs)
*/
// camera and camcorder need access to the ISurface binder interface for preview
friend class CameraService;
friend class MediaRecorder;
// MediaPlayer needs access to ISurface for display
friend class MediaPlayer;
friend class IOMX;
friend class SoftwareRenderer;
// this is just to be able to write some unit tests
friend class Test;
// videoEditor preview classes
friend class VideoEditorPreviewController;
friend class PreviewRenderer;
private:
friend class SurfaceComposerClient;
friend class SurfaceControl;
// can't be copied
@ -194,62 +172,27 @@ private:
Surface(const Parcel& data, const sp<IBinder>& ref);
~Surface();
/*
* ANativeWindow hooks
*/
static int setSwapInterval(ANativeWindow* window, int interval);
static int dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
static int cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
static int lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
static int queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
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);
int cancelBuffer(ANativeWindowBuffer* buffer);
int query(int what, int* value) const;
int perform(int operation, va_list args);
/*
* private stuff...
*/
void init();
status_t validate(bool inCancelBuffer = false) const;
int getConnectedApi() const;
static void cleanCachedSurfacesLocked();
virtual int query(int what, int* value) const;
// constants
status_t mInitCheck;
sp<ISurface> mSurface;
sp<SurfaceTextureClient> mSurfaceTextureClient;
uint32_t mIdentity;
PixelFormat mFormat;
uint32_t mFlags;
// protected by mSurfaceLock. These are also used from lock/unlock
// but in that case, they must be called form the same thread.
mutable Region mDirtyRegion;
// must be used from the lock/unlock thread
sp<GraphicBuffer> mLockedBuffer;
sp<GraphicBuffer> mPostedBuffer;
mutable Region mOldDirtyRegion;
bool mReserved;
// query() must be called from dequeueBuffer() thread
uint32_t mWidth;
uint32_t mHeight;
// Inherently thread-safe
mutable Mutex mSurfaceLock;
mutable Mutex mApiLock;
// A cache of Surface objects that have been deserialized into this process.
static Mutex sCachedSurfacesLock;
static DefaultKeyedVector<wp<IBinder>, wp<Surface> > sCachedSurfaces;

View File

@ -46,59 +46,6 @@
namespace android {
// ----------------------------------------------------------------------
static status_t copyBlt(
const sp<GraphicBuffer>& dst,
const sp<GraphicBuffer>& src,
const Region& reg)
{
// src and dst with, height and format must be identical. no verification
// is done here.
status_t err;
uint8_t const * src_bits = NULL;
err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits);
LOGE_IF(err, "error locking src buffer %s", strerror(-err));
uint8_t* dst_bits = NULL;
err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), (void**)&dst_bits);
LOGE_IF(err, "error locking dst buffer %s", strerror(-err));
Region::const_iterator head(reg.begin());
Region::const_iterator tail(reg.end());
if (head != tail && src_bits && dst_bits) {
const size_t bpp = bytesPerPixel(src->format);
const size_t dbpr = dst->stride * bpp;
const size_t sbpr = src->stride * bpp;
while (head != tail) {
const Rect& r(*head++);
ssize_t h = r.height();
if (h <= 0) continue;
size_t size = r.width() * bpp;
uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
if (dbpr==sbpr && size==sbpr) {
size *= h;
h = 1;
}
do {
memcpy(d, s, size);
d += dbpr;
s += sbpr;
} while (--h > 0);
}
}
if (src_bits)
src->unlock();
if (dst_bits)
dst->unlock();
return err;
}
// ============================================================================
// SurfaceControl
// ============================================================================
@ -277,7 +224,8 @@ sp<Surface> SurfaceControl::getSurface() const
// ---------------------------------------------------------------------------
Surface::Surface(const sp<SurfaceControl>& surface)
: mInitCheck(NO_INIT),
: SurfaceTextureClient(),
mInitCheck(NO_INIT),
mSurface(surface->mSurface),
mIdentity(surface->mIdentity),
mFormat(surface->mFormat), mFlags(surface->mFlags),
@ -287,7 +235,8 @@ Surface::Surface(const sp<SurfaceControl>& surface)
}
Surface::Surface(const Parcel& parcel, const sp<IBinder>& ref)
: mInitCheck(NO_INIT)
: SurfaceTextureClient(),
mInitCheck(NO_INIT)
{
mSurface = interface_cast<ISurface>(ref);
mIdentity = parcel.readInt32();
@ -363,36 +312,21 @@ void Surface::cleanCachedSurfacesLocked() {
void Surface::init()
{
ANativeWindow::setSwapInterval = setSwapInterval;
ANativeWindow::dequeueBuffer = dequeueBuffer;
ANativeWindow::cancelBuffer = cancelBuffer;
ANativeWindow::lockBuffer = lockBuffer;
ANativeWindow::queueBuffer = queueBuffer;
ANativeWindow::query = query;
ANativeWindow::perform = perform;
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);
setISurfaceTexture(surfaceTexture);
setUsage(GraphicBuffer::USAGE_HW_RENDER);
}
DisplayInfo dinfo;
SurfaceComposerClient::getDisplayInfo(0, &dinfo);
const_cast<float&>(ANativeWindow::xdpi) = dinfo.xdpi;
const_cast<float&>(ANativeWindow::ydpi) = dinfo.ydpi;
const_cast<int&>(ANativeWindow::minSwapInterval) =
mSurfaceTextureClient->minSwapInterval;
const_cast<int&>(ANativeWindow::maxSwapInterval) =
mSurfaceTextureClient->maxSwapInterval;
const_cast<uint32_t&>(ANativeWindow::flags) = 0;
if (mSurfaceTextureClient != 0) {
if (surfaceTexture != NULL) {
mInitCheck = NO_ERROR;
}
}
@ -402,7 +336,6 @@ Surface::~Surface()
{
// clear all references and trigger an IPC now, to make sure things
// happen without delay, since these resources are quite heavy.
mSurfaceTextureClient.clear();
mSurface.clear();
IPCThreadState::self()->flushCommands();
}
@ -431,77 +364,6 @@ sp<IBinder> Surface::asBinder() const {
// ----------------------------------------------------------------------------
int Surface::setSwapInterval(ANativeWindow* window, int interval) {
Surface* self = getSelf(window);
return self->setSwapInterval(interval);
}
int Surface::dequeueBuffer(ANativeWindow* window,
ANativeWindowBuffer** buffer) {
Surface* self = getSelf(window);
return self->dequeueBuffer(buffer);
}
int Surface::cancelBuffer(ANativeWindow* window,
ANativeWindowBuffer* buffer) {
Surface* self = getSelf(window);
return self->cancelBuffer(buffer);
}
int Surface::lockBuffer(ANativeWindow* window,
ANativeWindowBuffer* buffer) {
Surface* self = getSelf(window);
return self->lockBuffer(buffer);
}
int Surface::queueBuffer(ANativeWindow* window,
ANativeWindowBuffer* buffer) {
Surface* self = getSelf(window);
return self->queueBuffer(buffer);
}
int Surface::query(const ANativeWindow* window,
int what, int* value) {
const Surface* self = getSelf(window);
return self->query(what, value);
}
int Surface::perform(ANativeWindow* window,
int operation, ...) {
va_list args;
va_start(args, operation);
Surface* self = getSelf(window);
int res = self->perform(operation, args);
va_end(args);
return res;
}
// ----------------------------------------------------------------------------
int Surface::setSwapInterval(int interval) {
return mSurfaceTextureClient->setSwapInterval(interval);
}
int Surface::dequeueBuffer(ANativeWindowBuffer** buffer) {
status_t err = mSurfaceTextureClient->dequeueBuffer(buffer);
if (err == NO_ERROR) {
mDirtyRegion.set(buffer[0]->width, buffer[0]->height);
}
return err;
}
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_QUEUES_TO_WINDOW_COMPOSER:
@ -509,141 +371,39 @@ int Surface::query(int what, int* value) const {
*value = 1;
return NO_ERROR;
case NATIVE_WINDOW_CONCRETE_TYPE:
// TODO: this is not needed anymore
*value = NATIVE_WINDOW_SURFACE;
return NO_ERROR;
}
return mSurfaceTextureClient->query(what, value);
}
int Surface::perform(int operation, va_list args) {
return mSurfaceTextureClient->perform(operation, args);
return SurfaceTextureClient::query(what, value);
}
// ----------------------------------------------------------------------------
int Surface::getConnectedApi() const {
return mSurfaceTextureClient->getConnectedApi();
}
status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn) {
ANativeWindow_Buffer outBuffer;
// ----------------------------------------------------------------------------
status_t Surface::lock(SurfaceInfo* info, bool blocking) {
return Surface::lock(info, NULL, blocking);
}
status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking)
{
if (getConnectedApi()) {
LOGE("Surface::lock(%p) failed. Already connected to another API",
(ANativeWindow*)this);
CallStack stack;
stack.update();
stack.dump("");
return INVALID_OPERATION;
ARect temp;
ARect* inOutDirtyBounds = NULL;
if (dirtyIn) {
temp = dirtyIn->getBounds();
inOutDirtyBounds = &temp;
}
if (mApiLock.tryLock() != NO_ERROR) {
LOGE("calling Surface::lock from different threads!");
CallStack stack;
stack.update();
stack.dump("");
return WOULD_BLOCK;
}
status_t err = SurfaceTextureClient::lock(&outBuffer, inOutDirtyBounds);
/* Here we're holding mApiLock */
if (mLockedBuffer != 0) {
LOGE("Surface::lock failed, already locked");
mApiLock.unlock();
return INVALID_OPERATION;
}
// we're intending to do software rendering from this point
mSurfaceTextureClient->setUsage(
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
ANativeWindowBuffer* 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 = 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);
Region scratch(boundsRegion);
Region& newDirtyRegion(dirtyIn ? *dirtyIn : scratch);
newDirtyRegion &= boundsRegion;
// figure out if we can copy the frontbuffer back
const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
const bool canCopyBack = (frontBuffer != 0 &&
backBuffer->width == frontBuffer->width &&
backBuffer->height == frontBuffer->height &&
backBuffer->format == frontBuffer->format &&
!(mFlags & ISurfaceComposer::eDestroyBackbuffer));
// the dirty region we report to surfaceflinger is the one
// given by the user (as opposed to the one *we* return to the
// user).
mDirtyRegion = newDirtyRegion;
if (canCopyBack) {
// copy the area that is invalid and not repainted this round
const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));
if (!copyback.isEmpty())
copyBlt(backBuffer, frontBuffer, copyback);
} else {
// if we can't copy-back anything, modify the user's dirty
// region to make sure they redraw the whole buffer
newDirtyRegion = boundsRegion;
}
// keep track of the are of the buffer that is "clean"
// (ie: that will be redrawn)
mOldDirtyRegion = newDirtyRegion;
void* vaddr;
status_t res = backBuffer->lock(
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
newDirtyRegion.bounds(), &vaddr);
LOGW_IF(res, "failed locking buffer (handle = %p)",
backBuffer->handle);
mLockedBuffer = backBuffer;
other->w = backBuffer->width;
other->h = backBuffer->height;
other->s = backBuffer->stride;
other->usage = backBuffer->usage;
other->format = backBuffer->format;
other->bits = vaddr;
}
other->w = uint32_t(outBuffer.width);
other->h = uint32_t(outBuffer.height);
other->s = uint32_t(outBuffer.stride);
other->usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
other->format = uint32_t(outBuffer.format);
other->bits = outBuffer.bits;
}
mApiLock.unlock();
return err;
}
status_t Surface::unlockAndPost()
{
if (mLockedBuffer == 0) {
LOGE("Surface::unlockAndPost failed, no locked buffer");
return INVALID_OPERATION;
}
status_t err = mLockedBuffer->unlock();
LOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
err = mSurfaceTextureClient->queueBuffer(mLockedBuffer.get());
LOGE_IF(err, "queueBuffer (handle=%p) failed (%s)",
mLockedBuffer->handle, strerror(-err));
mPostedBuffer = mLockedBuffer;
mLockedBuffer = 0;
return err;
status_t Surface::unlockAndPost() {
return SurfaceTextureClient::unlockAndPost();
}
// ----------------------------------------------------------------------------

View File

@ -495,7 +495,7 @@ status_t SurfaceTexture::setTransform(uint32_t transform) {
}
status_t SurfaceTexture::connect(int api) {
LOGV("SurfaceTexture::connect");
LOGV("SurfaceTexture::connect(this=%p, %d)", this, api);
Mutex::Autolock lock(mMutex);
int err = NO_ERROR;
switch (api) {
@ -504,6 +504,8 @@ status_t SurfaceTexture::connect(int api) {
case NATIVE_WINDOW_API_MEDIA:
case NATIVE_WINDOW_API_CAMERA:
if (mConnectedApi != NO_CONNECTED_API) {
LOGE("connect: already connected (cur=%d, req=%d)",
mConnectedApi, api);
err = -EINVAL;
} else {
mConnectedApi = api;
@ -517,7 +519,7 @@ status_t SurfaceTexture::connect(int api) {
}
status_t SurfaceTexture::disconnect(int api) {
LOGV("SurfaceTexture::disconnect");
LOGV("SurfaceTexture::disconnect(this=%p, %d)", this, api);
Mutex::Autolock lock(mMutex);
int err = NO_ERROR;
switch (api) {
@ -528,6 +530,8 @@ status_t SurfaceTexture::disconnect(int api) {
if (mConnectedApi == api) {
mConnectedApi = NO_CONNECTED_API;
} else {
LOGE("disconnect: connected to another api (cur=%d, req=%d)",
mConnectedApi, api);
err = -EINVAL;
}
break;

View File

@ -24,24 +24,45 @@
namespace android {
SurfaceTextureClient::SurfaceTextureClient(
const sp<ISurfaceTexture>& surfaceTexture):
mSurfaceTexture(surfaceTexture), mAllocator(0), mReqWidth(0),
mReqHeight(0), mReqFormat(0), mReqUsage(0),
mTimestamp(NATIVE_WINDOW_TIMESTAMP_AUTO),
mQueryWidth(0), mQueryHeight(0), mQueryFormat(0),
mMutex() {
const sp<ISurfaceTexture>& surfaceTexture)
{
SurfaceTextureClient::init();
SurfaceTextureClient::setISurfaceTexture(surfaceTexture);
}
SurfaceTextureClient::SurfaceTextureClient() {
SurfaceTextureClient::init();
}
void SurfaceTextureClient::init() {
// Initialize the ANativeWindow function pointers.
ANativeWindow::setSwapInterval = setSwapInterval;
ANativeWindow::dequeueBuffer = dequeueBuffer;
ANativeWindow::cancelBuffer = cancelBuffer;
ANativeWindow::lockBuffer = lockBuffer;
ANativeWindow::queueBuffer = queueBuffer;
ANativeWindow::query = query;
ANativeWindow::perform = perform;
ANativeWindow::setSwapInterval = hook_setSwapInterval;
ANativeWindow::dequeueBuffer = hook_dequeueBuffer;
ANativeWindow::cancelBuffer = hook_cancelBuffer;
ANativeWindow::lockBuffer = hook_lockBuffer;
ANativeWindow::queueBuffer = hook_queueBuffer;
ANativeWindow::query = hook_query;
ANativeWindow::perform = hook_perform;
const_cast<int&>(ANativeWindow::minSwapInterval) = 0;
const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;
mReqWidth = 0;
mReqHeight = 0;
mReqFormat = 0;
mReqUsage = 0;
mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
mQueryWidth = 0;
mQueryHeight = 0;
mQueryFormat = 0;
mConnectedToCpu = false;
}
void SurfaceTextureClient::setISurfaceTexture(
const sp<ISurfaceTexture>& surfaceTexture)
{
mSurfaceTexture = surfaceTexture;
// Get a reference to the allocator.
mAllocator = mSurfaceTexture->getAllocator();
}
@ -50,42 +71,42 @@ sp<ISurfaceTexture> SurfaceTextureClient::getISurfaceTexture() const {
return mSurfaceTexture;
}
int SurfaceTextureClient::setSwapInterval(ANativeWindow* window, int interval) {
int SurfaceTextureClient::hook_setSwapInterval(ANativeWindow* window, int interval) {
SurfaceTextureClient* c = getSelf(window);
return c->setSwapInterval(interval);
}
int SurfaceTextureClient::dequeueBuffer(ANativeWindow* window,
int SurfaceTextureClient::hook_dequeueBuffer(ANativeWindow* window,
ANativeWindowBuffer** buffer) {
SurfaceTextureClient* c = getSelf(window);
return c->dequeueBuffer(buffer);
}
int SurfaceTextureClient::cancelBuffer(ANativeWindow* window,
int SurfaceTextureClient::hook_cancelBuffer(ANativeWindow* window,
ANativeWindowBuffer* buffer) {
SurfaceTextureClient* c = getSelf(window);
return c->cancelBuffer(buffer);
}
int SurfaceTextureClient::lockBuffer(ANativeWindow* window,
int SurfaceTextureClient::hook_lockBuffer(ANativeWindow* window,
ANativeWindowBuffer* buffer) {
SurfaceTextureClient* c = getSelf(window);
return c->lockBuffer(buffer);
}
int SurfaceTextureClient::queueBuffer(ANativeWindow* window,
int SurfaceTextureClient::hook_queueBuffer(ANativeWindow* window,
ANativeWindowBuffer* buffer) {
SurfaceTextureClient* c = getSelf(window);
return c->queueBuffer(buffer);
}
int SurfaceTextureClient::query(const ANativeWindow* window,
int SurfaceTextureClient::hook_query(const ANativeWindow* window,
int what, int* value) {
const SurfaceTextureClient* c = getSelf(window);
return c->query(what, value);
}
int SurfaceTextureClient::perform(ANativeWindow* window, int operation, ...) {
int SurfaceTextureClient::hook_perform(ANativeWindow* window, int operation, ...) {
va_list args;
va_start(args, operation);
SurfaceTextureClient* c = getSelf(window);
@ -219,7 +240,6 @@ int SurfaceTextureClient::query(int what, int* value) const {
*value = 0;
return NO_ERROR;
case NATIVE_WINDOW_CONCRETE_TYPE:
// TODO: this is not needed anymore
*value = NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT;
return NO_ERROR;
}
@ -260,6 +280,12 @@ int SurfaceTextureClient::perform(int operation, va_list args)
case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
res = dispatchSetBuffersFormat(args);
break;
case NATIVE_WINDOW_LOCK:
res = dispatchLock(args);
break;
case NATIVE_WINDOW_UNLOCK_AND_POST:
res = dispatchUnlockAndPost(args);
break;
default:
res = NAME_NOT_FOUND;
break;
@ -324,28 +350,37 @@ int SurfaceTextureClient::dispatchSetBuffersTimestamp(va_list args) {
return setBuffersTimestamp(timestamp);
}
int SurfaceTextureClient::dispatchLock(va_list args) {
ANativeWindow_Buffer* outBuffer = va_arg(args, ANativeWindow_Buffer*);
ARect* inOutDirtyBounds = va_arg(args, ARect*);
return lock(outBuffer, inOutDirtyBounds);
}
int SurfaceTextureClient::dispatchUnlockAndPost(va_list args) {
return unlockAndPost();
}
int SurfaceTextureClient::connect(int api) {
LOGV("SurfaceTextureClient::connect");
Mutex::Autolock lock(mMutex);
return mSurfaceTexture->connect(api);
int err = mSurfaceTexture->connect(api);
if (!err && api == NATIVE_WINDOW_API_CPU) {
mConnectedToCpu = true;
}
return err;
}
int SurfaceTextureClient::disconnect(int api) {
LOGV("SurfaceTextureClient::disconnect");
Mutex::Autolock lock(mMutex);
return mSurfaceTexture->disconnect(api);
int err = mSurfaceTexture->disconnect(api);
if (!err && api == NATIVE_WINDOW_API_CPU) {
mConnectedToCpu = false;
}
return err;
}
int SurfaceTextureClient::getConnectedApi() const
{
// XXX: This method will be going away shortly, and is currently bogus. It
// always returns "nothing is connected". It will go away once Surface gets
// updated to actually connect as the 'CPU' API when locking a buffer.
Mutex::Autolock lock(mMutex);
return 0;
}
int SurfaceTextureClient::setUsage(uint32_t reqUsage)
{
LOGV("SurfaceTextureClient::setUsage");
@ -443,4 +478,160 @@ void SurfaceTextureClient::freeAllBuffers() {
}
}
// ----------------------------------------------------------------------
// the lock/unlock APIs must be used from the same thread
static status_t copyBlt(
const sp<GraphicBuffer>& dst,
const sp<GraphicBuffer>& src,
const Region& reg)
{
// src and dst with, height and format must be identical. no verification
// is done here.
status_t err;
uint8_t const * src_bits = NULL;
err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits);
LOGE_IF(err, "error locking src buffer %s", strerror(-err));
uint8_t* dst_bits = NULL;
err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), (void**)&dst_bits);
LOGE_IF(err, "error locking dst buffer %s", strerror(-err));
Region::const_iterator head(reg.begin());
Region::const_iterator tail(reg.end());
if (head != tail && src_bits && dst_bits) {
const size_t bpp = bytesPerPixel(src->format);
const size_t dbpr = dst->stride * bpp;
const size_t sbpr = src->stride * bpp;
while (head != tail) {
const Rect& r(*head++);
ssize_t h = r.height();
if (h <= 0) continue;
size_t size = r.width() * bpp;
uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
if (dbpr==sbpr && size==sbpr) {
size *= h;
h = 1;
}
do {
memcpy(d, s, size);
d += dbpr;
s += sbpr;
} while (--h > 0);
}
}
if (src_bits)
src->unlock();
if (dst_bits)
dst->unlock();
return err;
}
// ----------------------------------------------------------------------------
status_t SurfaceTextureClient::lock(
ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
{
if (mLockedBuffer != 0) {
LOGE("Surface::lock failed, already locked");
return INVALID_OPERATION;
}
if (!mConnectedToCpu) {
int err = SurfaceTextureClient::connect(NATIVE_WINDOW_API_CPU);
if (err) {
return err;
}
// we're intending to do software rendering from this point
setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
}
ANativeWindowBuffer* out;
status_t err = 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 (handle=%p) failed (%s)",
backBuffer->handle, strerror(-err));
if (err == NO_ERROR) {
const Rect bounds(backBuffer->width, backBuffer->height);
Region newDirtyRegion;
if (inOutDirtyBounds) {
newDirtyRegion.set(static_cast<Rect const&>(*inOutDirtyBounds));
newDirtyRegion.andSelf(bounds);
} else {
newDirtyRegion.set(bounds);
}
// figure out if we can copy the frontbuffer back
const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
const bool canCopyBack = (frontBuffer != 0 &&
backBuffer->width == frontBuffer->width &&
backBuffer->height == frontBuffer->height &&
backBuffer->format == frontBuffer->format);
if (canCopyBack) {
// copy the area that is invalid and not repainted this round
const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));
if (!copyback.isEmpty())
copyBlt(backBuffer, frontBuffer, copyback);
} else {
// if we can't copy-back anything, modify the user's dirty
// region to make sure they redraw the whole buffer
newDirtyRegion.set(bounds);
}
// keep track of the are of the buffer that is "clean"
// (ie: that will be redrawn)
mOldDirtyRegion = newDirtyRegion;
if (inOutDirtyBounds) {
*inOutDirtyBounds = newDirtyRegion.getBounds();
}
void* vaddr;
status_t res = backBuffer->lock(
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
newDirtyRegion.bounds(), &vaddr);
LOGW_IF(res, "failed locking buffer (handle = %p)",
backBuffer->handle);
mLockedBuffer = backBuffer;
outBuffer->width = backBuffer->width;
outBuffer->height = backBuffer->height;
outBuffer->stride = backBuffer->stride;
outBuffer->format = backBuffer->format;
outBuffer->bits = vaddr;
}
}
return err;
}
status_t SurfaceTextureClient::unlockAndPost()
{
if (mLockedBuffer == 0) {
LOGE("Surface::unlockAndPost failed, no locked buffer");
return INVALID_OPERATION;
}
status_t err = mLockedBuffer->unlock();
LOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
err = queueBuffer(mLockedBuffer.get());
LOGE_IF(err, "queueBuffer (handle=%p) failed (%s)",
mLockedBuffer->handle, strerror(-err));
mPostedBuffer = mLockedBuffer;
mLockedBuffer = 0;
return err;
}
}; // namespace android

View File

@ -303,6 +303,10 @@ int FramebufferNativeWindow::perform(ANativeWindow* window,
case NATIVE_WINDOW_CONNECT:
case NATIVE_WINDOW_DISCONNECT:
break;
case NATIVE_WINDOW_LOCK:
return INVALID_OPERATION;
case NATIVE_WINDOW_UNLOCK_AND_POST:
return INVALID_OPERATION;
default:
return NAME_NOT_FOUND;
}