diff options
Diffstat (limited to 'libs/surfaceflinger_client/Surface.cpp')
| -rw-r--r-- | libs/surfaceflinger_client/Surface.cpp | 1152 |
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 |
