Integrate from //sandbox/mathias/donut/...@145728
SurfaceFlinger rework for new EGL driver model support.
diff --git a/libs/ui/Surface.cpp b/libs/ui/Surface.cpp
index 4ea9ae2..357e4d0 100644
--- a/libs/ui/Surface.cpp
+++ b/libs/ui/Surface.cpp
@@ -23,24 +23,126 @@
#include <sys/types.h>
#include <sys/stat.h>
-#include <utils/Atomic.h>
#include <utils/Errors.h>
#include <utils/threads.h>
#include <utils/IPCThreadState.h>
#include <utils/IMemory.h>
#include <utils/Log.h>
+#include <ui/DisplayInfo.h>
+#include <ui/BufferMapper.h>
+#include <ui/EGLNativeWindowSurface.h>
#include <ui/ISurface.h>
#include <ui/Surface.h>
#include <ui/SurfaceComposerClient.h>
#include <ui/Rect.h>
+#include <EGL/android_natives.h>
+
#include <private/ui/SharedState.h>
#include <private/ui/LayerState.h>
+#include <pixelflinger/pixelflinger.h>
+
namespace android {
-// ---------------------------------------------------------------------------
+// ============================================================================
+// SurfaceBuffer
+// ============================================================================
+
+SurfaceBuffer::SurfaceBuffer()
+ : BASE(), handle(0), mOwner(false)
+{
+ width =
+ height =
+ stride =
+ format =
+ usage = 0;
+ android_native_buffer_t::getHandle = getHandle;
+}
+
+SurfaceBuffer::SurfaceBuffer(const Parcel& data)
+ : BASE(), handle(0), mOwner(true)
+{
+ // we own the handle in this case
+ width = data.readInt32();
+ height = data.readInt32();
+ stride = data.readInt32();
+ format = data.readInt32();
+ usage = data.readInt32();
+ handle = data.readNativeHandle();
+ android_native_buffer_t::getHandle = getHandle;
+}
+
+SurfaceBuffer::~SurfaceBuffer()
+{
+ if (handle && mOwner) {
+ native_handle_close(handle);
+ native_handle_delete(const_cast<native_handle*>(handle));
+ }
+}
+
+int SurfaceBuffer::getHandle(android_native_buffer_t const * base,
+ buffer_handle_t* handle)
+{
+ *handle = getSelf(base)->handle;
+ return 0;
+}
+
+status_t SurfaceBuffer::writeToParcel(Parcel* reply,
+ android_native_buffer_t const* buffer)
+{
+ buffer_handle_t handle;
+ status_t err = buffer->getHandle(buffer, &handle);
+ if (err < 0) {
+ return err;
+ }
+ reply->writeInt32(buffer->width);
+ reply->writeInt32(buffer->height);
+ reply->writeInt32(buffer->stride);
+ reply->writeInt32(buffer->format);
+ reply->writeInt32(buffer->usage);
+ reply->writeNativeHandle(handle);
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------
+
+static void copyBlt(const android_native_buffer_t* dst,
+ const android_native_buffer_t* src, const Region& reg)
+{
+ Region::iterator iterator(reg);
+ if (iterator) {
+ // NOTE: dst and src must be the same format
+ Rect r;
+ const size_t bpp = bytesPerPixel(src->format);
+ const size_t dbpr = dst->stride * bpp;
+ const size_t sbpr = src->stride * bpp;
+ while (iterator.iterate(&r)) {
+ ssize_t h = r.bottom - r.top;
+ if (h) {
+ size_t size = (r.right - r.left) * bpp;
+ uint8_t* s = (GGLubyte*)src->bits +
+ (r.left + src->stride * r.top) * bpp;
+ uint8_t* d = (GGLubyte*)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);
+ }
+ }
+ }
+}
+
+// ============================================================================
+// Surface
+// ============================================================================
Surface::Surface(const sp<SurfaceComposerClient>& client,
const sp<ISurface>& surface,
@@ -51,26 +153,44 @@
mToken(data.token), mIdentity(data.identity),
mFormat(format), mFlags(flags), mOwner(owner)
{
+ android_native_window_t::connect = connect;
+ android_native_window_t::disconnect = disconnect;
+ android_native_window_t::setSwapInterval = setSwapInterval;
+ android_native_window_t::setSwapRectangle = setSwapRectangle;
+ android_native_window_t::dequeueBuffer = dequeueBuffer;
+ android_native_window_t::lockBuffer = lockBuffer;
+ android_native_window_t::queueBuffer = queueBuffer;
+
mSwapRectangle.makeInvalid();
- mSurfaceHeapBase[0] = 0;
- mSurfaceHeapBase[1] = 0;
- mHeap[0] = data.heap[0];
- mHeap[1] = data.heap[1];
+
+ DisplayInfo dinfo;
+ SurfaceComposerClient::getDisplayInfo(0, &dinfo);
+ const_cast<float&>(android_native_window_t::xdpi) = dinfo.xdpi;
+ const_cast<float&>(android_native_window_t::ydpi) = dinfo.ydpi;
+ // FIXME: set real values here
+ const_cast<int&>(android_native_window_t::minSwapInterval) = 1;
+ const_cast<int&>(android_native_window_t::maxSwapInterval) = 1;
+ const_cast<uint32_t&>(android_native_window_t::flags) = 0;
}
Surface::Surface(Surface const* rhs)
: mOwner(false)
{
- mToken = rhs->mToken;
- mIdentity= rhs->mIdentity;
- mClient = rhs->mClient;
- mSurface = rhs->mSurface;
- mHeap[0] = rhs->mHeap[0];
- mHeap[1] = rhs->mHeap[1];
- mFormat = rhs->mFormat;
- mFlags = rhs->mFlags;
- mSurfaceHeapBase[0] = rhs->mSurfaceHeapBase[0];
- mSurfaceHeapBase[1] = rhs->mSurfaceHeapBase[1];
+ // FIXME: we really should get rid of this ctor. the memcpy below
+ //should be safe for now, but android_native_window_t is not supposed
+ // to be clonable.
+ memcpy( static_cast<android_native_window_t*>(this),
+ static_cast<android_native_window_t const *>(rhs),
+ sizeof(android_native_window_t));
+
+ mToken = rhs->mToken;
+ mIdentity = rhs->mIdentity;
+ mClient = rhs->mClient;
+ mSurface = rhs->mSurface;
+ mBuffers[0] = rhs->mBuffers[0];
+ mBuffers[1] = rhs->mBuffers[1];
+ mFormat = rhs->mFormat;
+ mFlags = rhs->mFlags;
mSwapRectangle.makeInvalid();
}
@@ -78,21 +198,26 @@
{
if (mOwner && mToken>=0 && mClient!=0) {
mClient->destroySurface(mToken);
+ if (mBuffers[0] != 0) {
+ BufferMapper::get().unmap(mBuffers[0]->getHandle());
+ }
+ if (mBuffers[1] != 0) {
+ BufferMapper::get().unmap(mBuffers[1]->getHandle());
+ }
}
mClient.clear();
mSurface.clear();
- mHeap[0].clear();
- mHeap[1].clear();
IPCThreadState::self()->flushCommands();
}
sp<Surface> Surface::dup() const
{
+ // FIXME: we should get rid of Surface::dup()
Surface const * r = this;
if (this && mOwner) {
// the only reason we need to do this is because of Java's garbage
// collector: because we're creating a copy of the Surface
- // instead of a reference, we can garantee that when our last
+ // instead of a reference, we can guarantee that when our last
// reference goes away, the real surface will be deleted.
// Without this hack (the code is correct too), we'd have to
// wait for a GC for the surface to go away.
@@ -101,31 +226,244 @@
return const_cast<Surface*>(r);
}
-status_t Surface::nextBuffer(SurfaceInfo* info) {
- return mClient->nextBuffer(this, info);
+status_t Surface::validate(per_client_cblk_t const* cblk) const
+{
+ if (cblk == 0) {
+ LOGE("cblk is null (surface id=%d, identity=%u)", mToken, mIdentity);
+ return NO_INIT;
+ }
+ status_t err = cblk->validate(mToken);
+ if (err != NO_ERROR) {
+ LOGE("surface (id=%d, identity=%u) is invalid, err=%d (%s)",
+ mToken, mIdentity, err, strerror(-err));
+ return err;
+ }
+ if (mIdentity != uint32_t(cblk->layers[mToken].identity)) {
+ LOGE("using an invalid surface id=%d, identity=%u should be %d",
+ mToken, mIdentity, cblk->layers[mToken].identity);
+ return NO_INIT;
+ }
+ return NO_ERROR;
}
+// ----------------------------------------------------------------------------
+
+int Surface::setSwapRectangle(android_native_window_t* window,
+ int l, int t, int w, int h)
+{
+ Surface* self = getSelf(window);
+ self->setSwapRectangle(Rect(l, t, l+w, t+h));
+ return 0;
+}
+
+void Surface::connect(android_native_window_t* window)
+{
+}
+
+void Surface::disconnect(android_native_window_t* window)
+{
+}
+
+int Surface::setSwapInterval(android_native_window_t* window, int interval)
+{
+ return 0;
+}
+
+int Surface::dequeueBuffer(android_native_window_t* window,
+ android_native_buffer_t** buffer)
+{
+ Surface* self = getSelf(window);
+ return self->dequeueBuffer(buffer);
+}
+
+int Surface::lockBuffer(android_native_window_t* window,
+ android_native_buffer_t* buffer)
+{
+ Surface* self = getSelf(window);
+ return self->lockBuffer(buffer);
+}
+
+int Surface::queueBuffer(android_native_window_t* window,
+ android_native_buffer_t* buffer)
+{
+ Surface* self = getSelf(window);
+ return self->queueBuffer(buffer);
+}
+
+// ----------------------------------------------------------------------------
+
+int Surface::dequeueBuffer(android_native_buffer_t** buffer)
+{
+ // FIXME: dequeueBuffer() needs proper implementation
+
+ Mutex::Autolock _l(mSurfaceLock);
+
+ per_client_cblk_t* const cblk = mClient->mControl;
+ status_t err = validate(cblk);
+ if (err != NO_ERROR)
+ return err;
+
+ SurfaceID index(mToken);
+
+ int32_t backIdx = cblk->lock_layer(size_t(index),
+ per_client_cblk_t::BLOCKING);
+
+ if (backIdx < 0)
+ return status_t(backIdx);
+
+ mBackbufferIndex = backIdx;
+ layer_cblk_t* const lcblk = &(cblk->layers[index]);
+
+ volatile const surface_info_t* const back = lcblk->surface + backIdx;
+ if (back->flags & surface_info_t::eNeedNewBuffer) {
+ getBufferLocked(backIdx);
+ }
+
+ const sp<SurfaceBuffer>& backBuffer(mBuffers[backIdx]);
+ *buffer = backBuffer.get();
+
+ return NO_ERROR;
+}
+
+int Surface::lockBuffer(android_native_buffer_t* buffer)
+{
+ // FIXME: lockBuffer() needs proper implementation
+ return 0;
+}
+
+int Surface::queueBuffer(android_native_buffer_t* buffer)
+{
+ Mutex::Autolock _l(mSurfaceLock);
+
+ per_client_cblk_t* const cblk = mClient->mControl;
+ status_t err = validate(cblk);
+ if (err != NO_ERROR)
+ return err;
+
+ // transmit the dirty region
+ const Region dirty(swapRectangle());
+ SurfaceID index(mToken);
+ layer_cblk_t* const lcblk = &(cblk->layers[index]);
+ _send_dirty_region(lcblk, dirty);
+
+ uint32_t newstate = cblk->unlock_layer_and_post(size_t(index));
+ if (!(newstate & eNextFlipPending))
+ mClient->signalServer();
+
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
status_t Surface::lock(SurfaceInfo* info, bool blocking) {
return Surface::lock(info, NULL, blocking);
}
-status_t Surface::lock(SurfaceInfo* info, Region* dirty, bool blocking) {
- if (heapBase(0) == 0) return INVALID_OPERATION;
- if (heapBase(1) == 0) return INVALID_OPERATION;
- return mClient->lockSurface(this, info, dirty, blocking);
+status_t Surface::lock(SurfaceInfo* other, Region* dirty, bool blocking)
+{
+ // FIXME: needs some locking here
+ android_native_buffer_t* backBuffer;
+ status_t err = dequeueBuffer(&backBuffer);
+ if (err == NO_ERROR) {
+ err = lockBuffer(backBuffer);
+ if (err == NO_ERROR) {
+ backBuffer->common.incRef(&backBuffer->common);
+ mLockedBuffer = backBuffer;
+ other->w = backBuffer->width;
+ other->h = backBuffer->height;
+ other->s = backBuffer->stride;
+ other->usage = backBuffer->usage;
+ other->format = backBuffer->format;
+ other->bits = backBuffer->bits;
+
+ // we handle copy-back here...
+
+ const Rect bounds(backBuffer->width, backBuffer->height);
+ Region newDirtyRegion;
+
+ per_client_cblk_t* const cblk = mClient->mControl;
+ layer_cblk_t* const lcblk = &(cblk->layers[SurfaceID(mToken)]);
+ volatile const surface_info_t* const back = lcblk->surface + mBackbufferIndex;
+ if (back->flags & surface_info_t::eBufferDirty) {
+ // content is meaningless in this case and the whole surface
+ // needs to be redrawn.
+ newDirtyRegion.set(bounds);
+ if (dirty) {
+ *dirty = newDirtyRegion;
+ }
+ } else
+ {
+ if (dirty) {
+ dirty->andSelf(Region(bounds));
+ newDirtyRegion = *dirty;
+ } else {
+ newDirtyRegion.set(bounds);
+ }
+ Region copyback;
+ if (!(lcblk->flags & eNoCopyBack)) {
+ const Region previousDirtyRegion(dirtyRegion());
+ copyback = previousDirtyRegion.subtract(newDirtyRegion);
+ }
+ const sp<SurfaceBuffer>& frontBuffer(mBuffers[1-mBackbufferIndex]);
+ if (!copyback.isEmpty() && frontBuffer!=0) {
+ // copy front to back
+ copyBlt(backBuffer, frontBuffer.get(), copyback);
+ }
+ }
+ setDirtyRegion(newDirtyRegion);
+
+
+ Rect lockBounds(backBuffer->width, backBuffer->height);
+ if (dirty) {
+ lockBounds = dirty->bounds();
+ }
+ buffer_handle_t handle;
+ backBuffer->getHandle(backBuffer, &handle);
+ status_t res = BufferMapper::get().lock(handle,
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ lockBounds);
+ LOGW_IF(res, "failed locking buffer %d (%p)",
+ mBackbufferIndex, handle);
+ setSwapRectangle(lockBounds);
+ }
+ }
+ return err;
+}
+
+status_t Surface::unlockAndPost()
+{
+ // FIXME: needs some locking here
+
+ if (mLockedBuffer == 0)
+ return BAD_VALUE;
+
+ buffer_handle_t handle;
+ mLockedBuffer->getHandle(mLockedBuffer, &handle);
+ status_t res = BufferMapper::get().unlock(handle);
+ LOGW_IF(res, "failed unlocking buffer %d (%p)",
+ mBackbufferIndex, handle);
+
+ const Rect dirty(dirtyRegion().bounds());
+ setSwapRectangle(dirty);
+ status_t err = queueBuffer(mLockedBuffer);
+ mLockedBuffer->common.decRef(&mLockedBuffer->common);
+ mLockedBuffer = 0;
+ return err;
}
-status_t Surface::unlockAndPost() {
- if (heapBase(0) == 0) return INVALID_OPERATION;
- if (heapBase(1) == 0) return INVALID_OPERATION;
- return mClient->unlockAndPostSurface(this);
+void Surface::_send_dirty_region(
+ layer_cblk_t* lcblk, const Region& dirty)
+{
+ const int32_t index = (lcblk->flags & eBufferIndex) >> eBufferIndexShift;
+ flat_region_t* flat_region = lcblk->region + index;
+ status_t err = dirty.write(flat_region, sizeof(flat_region_t));
+ if (err < NO_ERROR) {
+ // region doesn't fit, use the bounds
+ const Region reg(dirty.bounds());
+ reg.write(flat_region, sizeof(flat_region_t));
+ }
}
-status_t Surface::unlock() {
- if (heapBase(0) == 0) return INVALID_OPERATION;
- if (heapBase(1) == 0) return INVALID_OPERATION;
- return mClient->unlockSurface(this);
-}
status_t Surface::setLayer(int32_t layer) {
return mClient->setLayer(this, layer);
@@ -183,8 +521,6 @@
ISurfaceFlingerClient::surface_data_t data;
sp<IBinder> clientBinder= parcel->readStrongBinder();
sp<ISurface> surface = interface_cast<ISurface>(parcel->readStrongBinder());
- data.heap[0] = interface_cast<IMemoryHeap>(parcel->readStrongBinder());
- data.heap[1] = interface_cast<IMemoryHeap>(parcel->readStrongBinder());
data.token = parcel->readInt32();
data.identity = parcel->readInt32();
PixelFormat format = parcel->readInt32();
@@ -204,21 +540,16 @@
uint32_t identity = 0;
sp<SurfaceComposerClient> client;
sp<ISurface> sur;
- sp<IMemoryHeap> heap[2];
if (surface->isValid()) {
token = surface->mToken;
identity = surface->mIdentity;
client = surface->mClient;
sur = surface->mSurface;
- heap[0] = surface->mHeap[0];
- heap[1] = surface->mHeap[1];
format = surface->mFormat;
flags = surface->mFlags;
}
parcel->writeStrongBinder(client!=0 ? client->connection() : NULL);
parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);
- parcel->writeStrongBinder(heap[0]!=0 ? heap[0]->asBinder() : NULL);
- parcel->writeStrongBinder(heap[1]!=0 ? heap[1]->asBinder() : NULL);
parcel->writeInt32(token);
parcel->writeInt32(identity);
parcel->writeInt32(format);
@@ -233,23 +564,24 @@
return lhs->mSurface->asBinder() == rhs->mSurface->asBinder();
}
-void* Surface::heapBase(int i) const
+status_t Surface::getBufferLocked(int index)
{
- void* heapBase = mSurfaceHeapBase[i];
- // map lazily so it doesn't get mapped in clients that don't need it
- if (heapBase == 0) {
- const sp<IMemoryHeap>& heap(mHeap[i]);
- if (heap != 0) {
- heapBase = static_cast<uint8_t*>(heap->base());
- if (heapBase == MAP_FAILED) {
- heapBase = NULL;
- LOGE("Couldn't map Surface's heap (binder=%p, heap=%p)",
- heap->asBinder().get(), heap.get());
- }
- mSurfaceHeapBase[i] = heapBase;
+ status_t err = NO_MEMORY;
+ sp<SurfaceBuffer> buffer = mSurface->getBuffer();
+ LOGE_IF(buffer==0, "ISurface::getBuffer() returned NULL");
+ if (buffer != 0) {
+ sp<SurfaceBuffer>& currentBuffer(mBuffers[index]);
+ if (currentBuffer != 0) {
+ BufferMapper::get().unmap(currentBuffer->getHandle());
+ currentBuffer.clear();
+ }
+ err = BufferMapper::get().map(buffer->getHandle(), &buffer->bits);
+ LOGW_IF(err, "map(...) failed %d (%s)", err, strerror(-err));
+ if (err == NO_ERROR) {
+ currentBuffer = buffer;
}
}
- return heapBase;
+ return err;
}
}; // namespace android