diff options
Diffstat (limited to 'libs/ui/Surface.cpp')
-rw-r--r-- | libs/ui/Surface.cpp | 440 |
1 files changed, 386 insertions, 54 deletions
diff --git a/libs/ui/Surface.cpp b/libs/ui/Surface.cpp index 4ea9ae2edbc0..357e4d0d5e5b 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 @@ Surface::Surface(const sp<SurfaceComposerClient>& client, 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 @@ Surface::~Surface() { 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,32 +226,245 @@ sp<Surface> Surface::dup() const 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; -status_t Surface::unlockAndPost() { - if (heapBase(0) == 0) return INVALID_OPERATION; - if (heapBase(1) == 0) return INVALID_OPERATION; - return mClient->unlockAndPostSurface(this); + 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::unlock() { - if (heapBase(0) == 0) return INVALID_OPERATION; - if (heapBase(1) == 0) return INVALID_OPERATION; - return mClient->unlockSurface(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::setLayer(int32_t layer) { return mClient->setLayer(this, layer); } @@ -183,8 +521,6 @@ sp<Surface> Surface::readFromParcel(Parcel* parcel) 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 @@ status_t Surface::writeToParcel(const sp<Surface>& surface, Parcel* parcel) 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 @@ bool Surface::isSameSurface(const sp<Surface>& lhs, const sp<Surface>& rhs) 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 |