summaryrefslogtreecommitdiffstats
path: root/libs/surfaceflinger_client/Surface.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/surfaceflinger_client/Surface.cpp')
-rw-r--r--libs/surfaceflinger_client/Surface.cpp1152
1 files changed, 0 insertions, 1152 deletions
diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp
deleted file mode 100644
index 0dfbf01..0000000
--- a/libs/surfaceflinger_client/Surface.cpp
+++ /dev/null
@@ -1,1152 +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 "Surface"
-
-#include <stdint.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <utils/Errors.h>
-#include <utils/threads.h>
-#include <utils/CallStack.h>
-#include <utils/Log.h>
-
-#include <binder/IPCThreadState.h>
-#include <binder/IMemory.h>
-
-#include <ui/DisplayInfo.h>
-#include <ui/GraphicBuffer.h>
-#include <ui/GraphicBufferMapper.h>
-#include <ui/GraphicLog.h>
-#include <ui/Rect.h>
-
-#include <surfaceflinger/Surface.h>
-#include <surfaceflinger/ISurface.h>
-#include <surfaceflinger/ISurfaceComposer.h>
-#include <surfaceflinger/SurfaceComposerClient.h>
-
-#include <private/surfaceflinger/SharedBufferStack.h>
-#include <private/surfaceflinger/LayerState.h>
-
-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
-// ============================================================================
-
-SurfaceControl::SurfaceControl(
- const sp<SurfaceComposerClient>& client,
- const sp<ISurface>& surface,
- const ISurfaceComposerClient::surface_data_t& data,
- uint32_t w, uint32_t h, PixelFormat format, uint32_t flags)
- : mClient(client), mSurface(surface),
- mToken(data.token), mIdentity(data.identity),
- mWidth(data.width), mHeight(data.height), mFormat(data.format),
- mFlags(flags)
-{
-}
-
-SurfaceControl::~SurfaceControl()
-{
- destroy();
-}
-
-void SurfaceControl::destroy()
-{
- if (isValid()) {
- mClient->destroySurface(mToken);
- }
-
- // clear all references and trigger an IPC now, to make sure things
- // happen without delay, since these resources are quite heavy.
- mClient.clear();
- mSurface.clear();
- IPCThreadState::self()->flushCommands();
-}
-
-void SurfaceControl::clear()
-{
- // here, the window manager tells us explicitly that we should destroy
- // the surface's resource. Soon after this call, it will also release
- // its last reference (which will call the dtor); however, it is possible
- // that a client living in the same process still holds references which
- // would delay the call to the dtor -- that is why we need this explicit
- // "clear()" call.
- destroy();
-}
-
-bool SurfaceControl::isSameSurface(
- const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs)
-{
- if (lhs == 0 || rhs == 0)
- return false;
- return lhs->mSurface->asBinder() == rhs->mSurface->asBinder();
-}
-
-status_t SurfaceControl::setLayer(int32_t layer) {
- status_t err = validate();
- if (err < 0) return err;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->setLayer(mToken, layer);
-}
-status_t SurfaceControl::setPosition(int32_t x, int32_t y) {
- status_t err = validate();
- if (err < 0) return err;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->setPosition(mToken, x, y);
-}
-status_t SurfaceControl::setSize(uint32_t w, uint32_t h) {
- status_t err = validate();
- if (err < 0) return err;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->setSize(mToken, w, h);
-}
-status_t SurfaceControl::hide() {
- status_t err = validate();
- if (err < 0) return err;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->hide(mToken);
-}
-status_t SurfaceControl::show(int32_t layer) {
- status_t err = validate();
- if (err < 0) return err;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->show(mToken, layer);
-}
-status_t SurfaceControl::freeze() {
- status_t err = validate();
- if (err < 0) return err;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->freeze(mToken);
-}
-status_t SurfaceControl::unfreeze() {
- status_t err = validate();
- if (err < 0) return err;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->unfreeze(mToken);
-}
-status_t SurfaceControl::setFlags(uint32_t flags, uint32_t mask) {
- status_t err = validate();
- if (err < 0) return err;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->setFlags(mToken, flags, mask);
-}
-status_t SurfaceControl::setTransparentRegionHint(const Region& transparent) {
- status_t err = validate();
- if (err < 0) return err;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->setTransparentRegionHint(mToken, transparent);
-}
-status_t SurfaceControl::setAlpha(float alpha) {
- status_t err = validate();
- if (err < 0) return err;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->setAlpha(mToken, alpha);
-}
-status_t SurfaceControl::setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
- status_t err = validate();
- if (err < 0) return err;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->setMatrix(mToken, dsdx, dtdx, dsdy, dtdy);
-}
-status_t SurfaceControl::setFreezeTint(uint32_t tint) {
- status_t err = validate();
- if (err < 0) return err;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->setFreezeTint(mToken, tint);
-}
-
-status_t SurfaceControl::validate() const
-{
- if (mToken<0 || mClient==0) {
- LOGE("invalid token (%d, identity=%u) or client (%p)",
- mToken, mIdentity, mClient.get());
- return NO_INIT;
- }
- return NO_ERROR;
-}
-
-status_t SurfaceControl::writeSurfaceToParcel(
- const sp<SurfaceControl>& control, Parcel* parcel)
-{
- sp<ISurface> sur;
- uint32_t identity = 0;
- uint32_t width = 0;
- uint32_t height = 0;
- uint32_t format = 0;
- uint32_t flags = 0;
- if (SurfaceControl::isValid(control)) {
- sur = control->mSurface;
- identity = control->mIdentity;
- width = control->mWidth;
- height = control->mHeight;
- format = control->mFormat;
- flags = control->mFlags;
- }
- parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);
- parcel->writeInt32(identity);
- parcel->writeInt32(width);
- parcel->writeInt32(height);
- parcel->writeInt32(format);
- parcel->writeInt32(flags);
- return NO_ERROR;
-}
-
-sp<Surface> SurfaceControl::getSurface() const
-{
- Mutex::Autolock _l(mLock);
- if (mSurfaceData == 0) {
- mSurfaceData = new Surface(const_cast<SurfaceControl*>(this));
- }
- return mSurfaceData;
-}
-
-// ============================================================================
-// 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),
- mSurface(surface->mSurface),
- mIdentity(surface->mIdentity),
- mFormat(surface->mFormat), mFlags(surface->mFlags),
- mWidth(surface->mWidth), mHeight(surface->mHeight)
-{
- init();
-}
-
-Surface::Surface(const Parcel& parcel, const sp<IBinder>& ref)
- : mBufferMapper(GraphicBufferMapper::get()),
- mClient(SurfaceClient::getInstance()),
- mSharedBufferClient(NULL),
- mInitCheck(NO_INIT)
-{
- mSurface = interface_cast<ISurface>(ref);
- mIdentity = parcel.readInt32();
- mWidth = parcel.readInt32();
- mHeight = parcel.readInt32();
- mFormat = parcel.readInt32();
- mFlags = parcel.readInt32();
- init();
-}
-
-status_t Surface::writeToParcel(
- const sp<Surface>& surface, Parcel* parcel)
-{
- sp<ISurface> sur;
- uint32_t identity = 0;
- uint32_t width = 0;
- uint32_t height = 0;
- uint32_t format = 0;
- uint32_t flags = 0;
- if (Surface::isValid(surface)) {
- sur = surface->mSurface;
- identity = surface->mIdentity;
- width = surface->mWidth;
- height = surface->mHeight;
- format = surface->mFormat;
- flags = surface->mFlags;
- } else if (surface != 0 && surface->mSurface != 0) {
- LOGW("Parceling invalid surface with non-NULL ISurface as NULL: "
- "mSurface = %p, mIdentity = %d, mWidth = %d, mHeight = %d, "
- "mFormat = %d, mFlags = 0x%08x, mInitCheck = %d",
- surface->mSurface.get(), surface->mIdentity, surface->mWidth,
- surface->mHeight, surface->mFormat, surface->mFlags,
- surface->mInitCheck);
- }
- parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);
- parcel->writeInt32(identity);
- parcel->writeInt32(width);
- parcel->writeInt32(height);
- parcel->writeInt32(format);
- parcel->writeInt32(flags);
- return NO_ERROR;
-
-}
-
-
-Mutex Surface::sCachedSurfacesLock;
-DefaultKeyedVector<wp<IBinder>, wp<Surface> > Surface::sCachedSurfaces;
-
-sp<Surface> Surface::readFromParcel(const Parcel& data) {
- Mutex::Autolock _l(sCachedSurfacesLock);
- sp<IBinder> binder(data.readStrongBinder());
- sp<Surface> surface = sCachedSurfaces.valueFor(binder).promote();
- if (surface == 0) {
- surface = new Surface(data, binder);
- sCachedSurfaces.add(binder, surface);
- }
- if (surface->mSurface == 0) {
- surface = 0;
- }
- cleanCachedSurfacesLocked();
- return surface;
-}
-
-// Remove the stale entries from the surface cache. This should only be called
-// with sCachedSurfacesLock held.
-void Surface::cleanCachedSurfacesLocked() {
- for (int i = sCachedSurfaces.size()-1; i >= 0; --i) {
- wp<Surface> s(sCachedSurfaces.valueAt(i));
- if (s == 0 || s.promote() == 0) {
- sCachedSurfaces.removeItemsAt(i);
- }
- }
-}
-
-void Surface::init()
-{
- ANativeWindow::setSwapInterval = setSwapInterval;
- ANativeWindow::dequeueBuffer = dequeueBuffer;
- ANativeWindow::cancelBuffer = cancelBuffer;
- ANativeWindow::lockBuffer = lockBuffer;
- ANativeWindow::queueBuffer = queueBuffer;
- 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;
-
- mNextBufferTransform = 0;
- mConnected = 0;
- mSwapRectangle.makeInvalid();
- mNextBufferCrop = Rect(0,0);
- // two buffers by default
- mBuffers.setCapacity(2);
- mBuffers.insertAt(0, 2);
-
- 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);
- }
- }
-}
-
-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();
- mSurface.clear();
- delete mSharedBufferClient;
- IPCThreadState::self()->flushCommands();
-}
-
-bool Surface::isValid() {
- return mInitCheck == NO_ERROR;
-}
-
-status_t Surface::validate(bool inCancelBuffer) const
-{
- // check that we initialized ourself properly
- if (mInitCheck != NO_ERROR) {
- 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;
-}
-
-sp<ISurface> Surface::getISurface() const {
- return mSurface;
-}
-
-// ----------------------------------------------------------------------------
-
-int Surface::setSwapInterval(ANativeWindow* window, int interval) {
- return 0;
-}
-
-int Surface::dequeueBuffer(ANativeWindow* window,
- android_native_buffer_t** buffer) {
- Surface* self = getSelf(window);
- return self->dequeueBuffer(buffer);
-}
-
-int Surface::cancelBuffer(ANativeWindow* window,
- android_native_buffer_t* buffer) {
- Surface* self = getSelf(window);
- return self->cancelBuffer(buffer);
-}
-
-int Surface::lockBuffer(ANativeWindow* window,
- android_native_buffer_t* buffer) {
- Surface* self = getSelf(window);
- return self->lockBuffer(buffer);
-}
-
-int Surface::queueBuffer(ANativeWindow* window,
- android_native_buffer_t* buffer) {
- Surface* self = getSelf(window);
- return self->queueBuffer(buffer);
-}
-
-int Surface::query(ANativeWindow* window,
- int what, int* value) {
- 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;
-}
-
-// ----------------------------------------------------------------------------
-
-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::dequeueBuffer(android_native_buffer_t** 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;
- }
-
- if (err == NO_ERROR) {
- mDirtyRegion.set(backBuffer->width, backBuffer->height);
- *buffer = backBuffer.get();
- } else {
- mSharedBufferClient->undoDequeue(bufIdx);
- }
-
- return err;
-}
-
-int Surface::cancelBuffer(android_native_buffer_t* 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(android_native_buffer_t* 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(android_native_buffer_t* 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();
- }
- return err;
-}
-
-int Surface::query(int what, int* value)
-{
- switch (what) {
- case NATIVE_WINDOW_WIDTH:
- *value = int(mWidth);
- 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:
- *value = NATIVE_WINDOW_SURFACE;
- return NO_ERROR;
- }
- return BAD_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::getConnectedApi() const
-{
- Mutex::Autolock _l(mSurfaceLock);
- return mConnected;
-}
-
-// ----------------------------------------------------------------------------
-
-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;
- }
-
- if (mApiLock.tryLock() != NO_ERROR) {
- LOGE("calling Surface::lock from different threads!");
- CallStack stack;
- stack.update();
- stack.dump("");
- return WOULD_BLOCK;
- }
-
- /* 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
- setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
-
- android_native_buffer_t* 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 (idx=%d) failed (%s)",
- getBufferIndex(backBuffer), 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;
- }
- }
- 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 = queueBuffer(mLockedBuffer.get());
- LOGE_IF(err, "queueBuffer (idx=%d) failed (%s)",
- getBufferIndex(mLockedBuffer), 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 android_native_buffer_t 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