Refactoring: Rename SurfaceTextureClient to Surface
Change-Id: Ibed34175ae273608393aaa5f0a7df207dc40d709
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 81fc019..410ad5d 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2010 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.
@@ -15,359 +15,851 @@
*/
#define LOG_TAG "Surface"
-
-#include <stdint.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+//#define LOG_NDEBUG 0
#include <android/native_window.h>
-#include <utils/CallStack.h>
-#include <utils/Errors.h>
+#include <binder/Parcel.h>
+
#include <utils/Log.h>
-#include <utils/threads.h>
+#include <utils/Trace.h>
-#include <binder/IPCThreadState.h>
+#include <ui/Fence.h>
-#include <ui/DisplayInfo.h>
-#include <ui/GraphicBuffer.h>
-#include <ui/Rect.h>
-
-#include <gui/ISurface.h>
#include <gui/ISurfaceComposer.h>
-#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
-#include <gui/SurfaceTextureClient.h>
+#include <gui/GLConsumer.h>
+#include <gui/Surface.h>
+
+#include <private/gui/ComposerService.h>
namespace android {
-// ============================================================================
-// SurfaceControl
-// ============================================================================
-
-SurfaceControl::SurfaceControl(
- const sp<SurfaceComposerClient>& client,
- const sp<ISurface>& surface)
- : mClient(client)
+Surface::Surface(
+ const sp<IGraphicBufferProducer>& bufferProducer)
{
- if (surface != 0) {
- mSurface = surface->asBinder();
+ Surface::init();
+ Surface::setIGraphicBufferProducer(bufferProducer);
+}
+
+Surface::Surface() {
+ Surface::init();
+}
+
+Surface::~Surface() {
+ if (mConnectedToCpu) {
+ Surface::disconnect(NATIVE_WINDOW_API_CPU);
}
}
-
-SurfaceControl::~SurfaceControl()
-{
- destroy();
+
+void Surface::init() {
+ // Initialize the ANativeWindow function pointers.
+ ANativeWindow::setSwapInterval = hook_setSwapInterval;
+ ANativeWindow::dequeueBuffer = hook_dequeueBuffer;
+ ANativeWindow::cancelBuffer = hook_cancelBuffer;
+ ANativeWindow::queueBuffer = hook_queueBuffer;
+ ANativeWindow::query = hook_query;
+ ANativeWindow::perform = hook_perform;
+
+ ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED;
+ ANativeWindow::cancelBuffer_DEPRECATED = hook_cancelBuffer_DEPRECATED;
+ ANativeWindow::lockBuffer_DEPRECATED = hook_lockBuffer_DEPRECATED;
+ ANativeWindow::queueBuffer_DEPRECATED = hook_queueBuffer_DEPRECATED;
+
+ const_cast<int&>(ANativeWindow::minSwapInterval) = 0;
+ const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;
+
+ mReqWidth = 0;
+ mReqHeight = 0;
+ mReqFormat = 0;
+ mReqUsage = 0;
+ mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
+ mCrop.clear();
+ mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
+ mTransform = 0;
+ mDefaultWidth = 0;
+ mDefaultHeight = 0;
+ mUserWidth = 0;
+ mUserHeight = 0;
+ mTransformHint = 0;
+ mConsumerRunningBehind = false;
+ mConnectedToCpu = false;
}
-void SurfaceControl::destroy()
+void Surface::setIGraphicBufferProducer(
+ const sp<IGraphicBufferProducer>& bufferProducer)
{
- if (isValid()) {
- mClient->destroySurface(mSurface);
+ mGraphicBufferProducer = bufferProducer;
+}
+
+sp<IGraphicBufferProducer> Surface::getIGraphicBufferProducer() const {
+ return mGraphicBufferProducer;
+}
+
+int Surface::hook_setSwapInterval(ANativeWindow* window, int interval) {
+ Surface* c = getSelf(window);
+ return c->setSwapInterval(interval);
+}
+
+int Surface::hook_dequeueBuffer(ANativeWindow* window,
+ ANativeWindowBuffer** buffer, int* fenceFd) {
+ Surface* c = getSelf(window);
+ return c->dequeueBuffer(buffer, fenceFd);
+}
+
+int Surface::hook_cancelBuffer(ANativeWindow* window,
+ ANativeWindowBuffer* buffer, int fenceFd) {
+ Surface* c = getSelf(window);
+ return c->cancelBuffer(buffer, fenceFd);
+}
+
+int Surface::hook_queueBuffer(ANativeWindow* window,
+ ANativeWindowBuffer* buffer, int fenceFd) {
+ Surface* c = getSelf(window);
+ return c->queueBuffer(buffer, fenceFd);
+}
+
+int Surface::hook_dequeueBuffer_DEPRECATED(ANativeWindow* window,
+ ANativeWindowBuffer** buffer) {
+ Surface* c = getSelf(window);
+ ANativeWindowBuffer* buf;
+ int fenceFd = -1;
+ int result = c->dequeueBuffer(&buf, &fenceFd);
+ sp<Fence> fence(new Fence(fenceFd));
+ int waitResult = fence->waitForever(1000, "dequeueBuffer_DEPRECATED");
+ if (waitResult != OK) {
+ ALOGE("dequeueBuffer_DEPRECATED: Fence::wait returned an error: %d",
+ waitResult);
+ c->cancelBuffer(buf, -1);
+ return waitResult;
}
- // 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();
+ *buffer = buf;
+ return result;
}
-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();
+int Surface::hook_cancelBuffer_DEPRECATED(ANativeWindow* window,
+ ANativeWindowBuffer* buffer) {
+ Surface* c = getSelf(window);
+ return c->cancelBuffer(buffer, -1);
}
-bool SurfaceControl::isSameSurface(
- const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs)
-{
- if (lhs == 0 || rhs == 0)
- return false;
- return lhs->mSurface == rhs->mSurface;
+int Surface::hook_lockBuffer_DEPRECATED(ANativeWindow* window,
+ ANativeWindowBuffer* buffer) {
+ Surface* c = getSelf(window);
+ return c->lockBuffer_DEPRECATED(buffer);
}
-status_t SurfaceControl::setLayerStack(int32_t layerStack) {
- status_t err = validate();
- if (err < 0) return err;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->setLayerStack(mSurface, layerStack);
-}
-status_t SurfaceControl::setLayer(int32_t layer) {
- status_t err = validate();
- if (err < 0) return err;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->setLayer(mSurface, 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(mSurface, 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(mSurface, w, h);
-}
-status_t SurfaceControl::hide() {
- status_t err = validate();
- if (err < 0) return err;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->hide(mSurface);
-}
-status_t SurfaceControl::show() {
- status_t err = validate();
- if (err < 0) return err;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->show(mSurface);
-}
-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(mSurface, 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(mSurface, transparent);
-}
-status_t SurfaceControl::setAlpha(float alpha) {
- status_t err = validate();
- if (err < 0) return err;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->setAlpha(mSurface, 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(mSurface, dsdx, dtdx, dsdy, dtdy);
-}
-status_t SurfaceControl::setCrop(const Rect& crop) {
- status_t err = validate();
- if (err < 0) return err;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->setCrop(mSurface, crop);
+int Surface::hook_queueBuffer_DEPRECATED(ANativeWindow* window,
+ ANativeWindowBuffer* buffer) {
+ Surface* c = getSelf(window);
+ return c->queueBuffer(buffer, -1);
}
-status_t SurfaceControl::validate() const
-{
- if (mSurface==0 || mClient==0) {
- ALOGE("invalid ISurface (%p) or client (%p)",
- mSurface.get(), mClient.get());
- return NO_INIT;
+int Surface::hook_query(const ANativeWindow* window,
+ int what, int* value) {
+ const Surface* c = getSelf(window);
+ return c->query(what, value);
+}
+
+int Surface::hook_perform(ANativeWindow* window, int operation, ...) {
+ va_list args;
+ va_start(args, operation);
+ Surface* c = getSelf(window);
+ return c->perform(operation, args);
+}
+
+int Surface::setSwapInterval(int interval) {
+ ATRACE_CALL();
+ // EGL specification states:
+ // interval is silently clamped to minimum and maximum implementation
+ // dependent values before being stored.
+ // Although we don't have to, we apply the same logic here.
+
+ if (interval < minSwapInterval)
+ interval = minSwapInterval;
+
+ if (interval > maxSwapInterval)
+ interval = maxSwapInterval;
+
+ status_t res = mGraphicBufferProducer->setSynchronousMode(interval ? true : false);
+
+ return res;
+}
+
+int Surface::dequeueBuffer(android_native_buffer_t** buffer,
+ int* fenceFd) {
+ ATRACE_CALL();
+ ALOGV("Surface::dequeueBuffer");
+ Mutex::Autolock lock(mMutex);
+ int buf = -1;
+ int reqW = mReqWidth ? mReqWidth : mUserWidth;
+ int reqH = mReqHeight ? mReqHeight : mUserHeight;
+ sp<Fence> fence;
+ status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, fence, reqW, reqH,
+ mReqFormat, mReqUsage);
+ if (result < 0) {
+ ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer(%d, %d, %d, %d)"
+ "failed: %d", mReqWidth, mReqHeight, mReqFormat, mReqUsage,
+ result);
+ return result;
}
- return NO_ERROR;
-}
-
-status_t SurfaceControl::writeSurfaceToParcel(
- const sp<SurfaceControl>& control, Parcel* parcel)
-{
- sp<IBinder> sur;
- if (SurfaceControl::isValid(control)) {
- sur = control->mSurface;
- }
- parcel->writeStrongBinder(sur);
- parcel->writeStrongBinder(NULL); // NULL IGraphicBufferProducer in this case.
- return NO_ERROR;
-}
-
-sp<Surface> SurfaceControl::getSurface() const
-{
- Mutex::Autolock _l(mLock);
- if (mSurfaceData == 0) {
- sp<SurfaceControl> surface_control(const_cast<SurfaceControl*>(this));
- mSurfaceData = new Surface(surface_control);
- }
- return mSurfaceData;
-}
-
-// ============================================================================
-// Surface
-// ============================================================================
-
-Surface::Surface(const sp<SurfaceControl>& surface)
- : SurfaceTextureClient()
-{
- mSurface = interface_cast<ISurface>(surface->mSurface);
- sp<IGraphicBufferProducer> st;
- if (mSurface != NULL) {
- st = mSurface->getSurfaceTexture();
- }
- init(st);
-}
-
-Surface::Surface(const Parcel& parcel, const sp<IBinder>& ref)
- : SurfaceTextureClient()
-{
- mSurface = interface_cast<ISurface>(ref);
- sp<IBinder> st_binder(parcel.readStrongBinder());
- sp<IGraphicBufferProducer> st;
- if (st_binder != NULL) {
- st = interface_cast<IGraphicBufferProducer>(st_binder);
- } else if (mSurface != NULL) {
- st = mSurface->getSurfaceTexture();
- }
- init(st);
-}
-
-Surface::Surface(const sp<IGraphicBufferProducer>& st)
- : SurfaceTextureClient(),
- mSurface(NULL)
-{
- init(st);
-}
-
-status_t Surface::writeToParcel(
- const sp<Surface>& surface, Parcel* parcel)
-{
- sp<ISurface> sur;
- sp<IGraphicBufferProducer> st;
- uint32_t identity = 0;
- if (Surface::isValid(surface)) {
- sur = surface->mSurface;
- st = surface->getISurfaceTexture();
- } else if (surface != 0 &&
- (surface->mSurface != NULL ||
- surface->getISurfaceTexture() != NULL)) {
- ALOGE("Parceling invalid surface with non-NULL ISurface/IGraphicBufferProducer "
- "as NULL: mSurface = %p, bufferProducer = %p ",
- surface->mSurface.get(), surface->getISurfaceTexture().get());
+ sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);
+ if (result & IGraphicBufferProducer::RELEASE_ALL_BUFFERS) {
+ freeAllBuffers();
}
- parcel->writeStrongBinder(sur != NULL ? sur->asBinder() : NULL);
- parcel->writeStrongBinder(st != NULL ? st->asBinder() : NULL);
- return NO_ERROR;
+ if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
+ result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
+ if (result != NO_ERROR) {
+ ALOGE("dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: %d",
+ result);
+ return result;
+ }
+ }
-}
-
-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 (fence->isValid()) {
+ *fenceFd = fence->dup();
+ if (*fenceFd == -1) {
+ ALOGE("dequeueBuffer: error duping fence: %d", errno);
+ // dup() should never fail; something is badly wrong. Soldier on
+ // and hope for the best; the worst that should happen is some
+ // visible corruption that lasts until the next frame.
+ }
} else {
- // The Surface was found in the cache, but we still should clear any
- // remaining data from the parcel.
- data.readStrongBinder(); // IGraphicBufferProducer
- data.readInt32(); // identity
+ *fenceFd = -1;
}
- if (surface->mSurface == NULL && surface->getISurfaceTexture() == NULL) {
- surface = 0;
- }
- cleanCachedSurfacesLocked();
- return surface;
+
+ *buffer = gbuf.get();
+ return OK;
}
-// 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);
+int Surface::cancelBuffer(android_native_buffer_t* buffer,
+ int fenceFd) {
+ ATRACE_CALL();
+ ALOGV("Surface::cancelBuffer");
+ Mutex::Autolock lock(mMutex);
+ int i = getSlotFromBufferLocked(buffer);
+ if (i < 0) {
+ return i;
+ }
+ sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
+ mGraphicBufferProducer->cancelBuffer(i, fence);
+ return OK;
+}
+
+int Surface::getSlotFromBufferLocked(
+ android_native_buffer_t* buffer) const {
+ bool dumpedState = false;
+ for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+ if (mSlots[i].buffer != NULL &&
+ mSlots[i].buffer->handle == buffer->handle) {
+ return i;
}
}
+ ALOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle);
+ return BAD_VALUE;
}
-void Surface::init(const sp<IGraphicBufferProducer>& bufferProducer)
-{
- if (mSurface != NULL || bufferProducer != NULL) {
- ALOGE_IF(bufferProducer==0, "got a NULL IGraphicBufferProducer from ISurface");
- if (bufferProducer != NULL) {
- setISurfaceTexture(bufferProducer);
- setUsage(GraphicBuffer::USAGE_HW_RENDER);
- }
+int Surface::lockBuffer_DEPRECATED(android_native_buffer_t* buffer) {
+ ALOGV("Surface::lockBuffer");
+ Mutex::Autolock lock(mMutex);
+ return OK;
+}
- // TODO: the display metrics should come from the display manager
- DisplayInfo dinfo;
- sp<IBinder> display = SurfaceComposerClient::getBuiltInDisplay(
- ISurfaceComposer::eDisplayIdMain);
- SurfaceComposerClient::getDisplayInfo(display, &dinfo);
- const_cast<float&>(ANativeWindow::xdpi) = dinfo.xdpi;
- const_cast<float&>(ANativeWindow::ydpi) = dinfo.ydpi;
- const_cast<uint32_t&>(ANativeWindow::flags) = 0;
+int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {
+ ATRACE_CALL();
+ ALOGV("Surface::queueBuffer");
+ Mutex::Autolock lock(mMutex);
+ int64_t timestamp;
+ if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) {
+ timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
+ ALOGV("Surface::queueBuffer making up timestamp: %.2f ms",
+ timestamp / 1000000.f);
+ } else {
+ timestamp = mTimestamp;
}
-}
+ int i = getSlotFromBufferLocked(buffer);
+ if (i < 0) {
+ return i;
+ }
-Surface::~Surface()
-{
- // clear all references and trigger an IPC now, to make sure things
- // happen without delay, since these resources are quite heavy.
- mSurface.clear();
- IPCThreadState::self()->flushCommands();
-}
-bool Surface::isValid() {
- return getISurfaceTexture() != NULL;
-}
+ // Make sure the crop rectangle is entirely inside the buffer.
+ Rect crop;
+ mCrop.intersect(Rect(buffer->width, buffer->height), &crop);
-sp<IGraphicBufferProducer> Surface::getSurfaceTexture() {
- return getISurfaceTexture();
-}
+ sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
+ IGraphicBufferProducer::QueueBufferOutput output;
+ IGraphicBufferProducer::QueueBufferInput input(timestamp, crop, mScalingMode,
+ mTransform, fence);
+ status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output);
+ if (err != OK) {
+ ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err);
+ }
+ uint32_t numPendingBuffers = 0;
+ output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint,
+ &numPendingBuffers);
-sp<IBinder> Surface::asBinder() const {
- return mSurface!=0 ? mSurface->asBinder() : 0;
-}
+ mConsumerRunningBehind = (numPendingBuffers >= 2);
-// ----------------------------------------------------------------------------
+ return err;
+}
int Surface::query(int what, int* value) const {
- switch (what) {
- case NATIVE_WINDOW_CONCRETE_TYPE:
- *value = NATIVE_WINDOW_SURFACE;
- return NO_ERROR;
+ ATRACE_CALL();
+ ALOGV("Surface::query");
+ { // scope for the lock
+ Mutex::Autolock lock(mMutex);
+ switch (what) {
+ case NATIVE_WINDOW_FORMAT:
+ if (mReqFormat) {
+ *value = mReqFormat;
+ return NO_ERROR;
+ }
+ break;
+ case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: {
+ sp<ISurfaceComposer> composer(
+ ComposerService::getComposerService());
+ if (composer->authenticateSurfaceTexture(mGraphicBufferProducer)) {
+ *value = 1;
+ } else {
+ *value = 0;
+ }
+ return NO_ERROR;
+ }
+ case NATIVE_WINDOW_CONCRETE_TYPE:
+ *value = NATIVE_WINDOW_SURFACE;
+ return NO_ERROR;
+ case NATIVE_WINDOW_DEFAULT_WIDTH:
+ *value = mUserWidth ? mUserWidth : mDefaultWidth;
+ return NO_ERROR;
+ case NATIVE_WINDOW_DEFAULT_HEIGHT:
+ *value = mUserHeight ? mUserHeight : mDefaultHeight;
+ return NO_ERROR;
+ case NATIVE_WINDOW_TRANSFORM_HINT:
+ *value = mTransformHint;
+ return NO_ERROR;
+ case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: {
+ status_t err = NO_ERROR;
+ if (!mConsumerRunningBehind) {
+ *value = 0;
+ } else {
+ err = mGraphicBufferProducer->query(what, value);
+ if (err == NO_ERROR) {
+ mConsumerRunningBehind = *value;
+ }
+ }
+ return err;
+ }
+ }
}
- return SurfaceTextureClient::query(what, value);
+ return mGraphicBufferProducer->query(what, value);
}
-// ----------------------------------------------------------------------------
+int Surface::perform(int operation, va_list args)
+{
+ int res = NO_ERROR;
+ switch (operation) {
+ case NATIVE_WINDOW_CONNECT:
+ // deprecated. must return NO_ERROR.
+ break;
+ case NATIVE_WINDOW_DISCONNECT:
+ // deprecated. must return NO_ERROR.
+ break;
+ case NATIVE_WINDOW_SET_USAGE:
+ res = dispatchSetUsage(args);
+ break;
+ case NATIVE_WINDOW_SET_CROP:
+ res = dispatchSetCrop(args);
+ break;
+ case NATIVE_WINDOW_SET_BUFFER_COUNT:
+ res = dispatchSetBufferCount(args);
+ break;
+ case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
+ res = dispatchSetBuffersGeometry(args);
+ break;
+ case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
+ res = dispatchSetBuffersTransform(args);
+ break;
+ case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
+ res = dispatchSetBuffersTimestamp(args);
+ break;
+ case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
+ res = dispatchSetBuffersDimensions(args);
+ break;
+ case NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS:
+ res = dispatchSetBuffersUserDimensions(args);
+ break;
+ case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
+ res = dispatchSetBuffersFormat(args);
+ break;
+ case NATIVE_WINDOW_LOCK:
+ res = dispatchLock(args);
+ break;
+ case NATIVE_WINDOW_UNLOCK_AND_POST:
+ res = dispatchUnlockAndPost(args);
+ break;
+ case NATIVE_WINDOW_SET_SCALING_MODE:
+ res = dispatchSetScalingMode(args);
+ break;
+ case NATIVE_WINDOW_API_CONNECT:
+ res = dispatchConnect(args);
+ break;
+ case NATIVE_WINDOW_API_DISCONNECT:
+ res = dispatchDisconnect(args);
+ break;
+ default:
+ res = NAME_NOT_FOUND;
+ break;
+ }
+ return res;
+}
-status_t Surface::lock(SurfaceInfo* other, Region* inOutDirtyRegion) {
- ANativeWindow_Buffer outBuffer;
+int Surface::dispatchConnect(va_list args) {
+ int api = va_arg(args, int);
+ return connect(api);
+}
- ARect temp;
- ARect* inOutDirtyBounds = NULL;
- if (inOutDirtyRegion) {
- temp = inOutDirtyRegion->getBounds();
- inOutDirtyBounds = &temp;
+int Surface::dispatchDisconnect(va_list args) {
+ int api = va_arg(args, int);
+ return disconnect(api);
+}
+
+int Surface::dispatchSetUsage(va_list args) {
+ int usage = va_arg(args, int);
+ return setUsage(usage);
+}
+
+int Surface::dispatchSetCrop(va_list args) {
+ android_native_rect_t const* rect = va_arg(args, android_native_rect_t*);
+ return setCrop(reinterpret_cast<Rect const*>(rect));
+}
+
+int Surface::dispatchSetBufferCount(va_list args) {
+ size_t bufferCount = va_arg(args, size_t);
+ return setBufferCount(bufferCount);
+}
+
+int Surface::dispatchSetBuffersGeometry(va_list args) {
+ int w = va_arg(args, int);
+ int h = va_arg(args, int);
+ int f = va_arg(args, int);
+ int err = setBuffersDimensions(w, h);
+ if (err != 0) {
+ return err;
+ }
+ return setBuffersFormat(f);
+}
+
+int Surface::dispatchSetBuffersDimensions(va_list args) {
+ int w = va_arg(args, int);
+ int h = va_arg(args, int);
+ return setBuffersDimensions(w, h);
+}
+
+int Surface::dispatchSetBuffersUserDimensions(va_list args) {
+ int w = va_arg(args, int);
+ int h = va_arg(args, int);
+ return setBuffersUserDimensions(w, h);
+}
+
+int Surface::dispatchSetBuffersFormat(va_list args) {
+ int f = va_arg(args, int);
+ return setBuffersFormat(f);
+}
+
+int Surface::dispatchSetScalingMode(va_list args) {
+ int m = va_arg(args, int);
+ return setScalingMode(m);
+}
+
+int Surface::dispatchSetBuffersTransform(va_list args) {
+ int transform = va_arg(args, int);
+ return setBuffersTransform(transform);
+}
+
+int Surface::dispatchSetBuffersTimestamp(va_list args) {
+ int64_t timestamp = va_arg(args, int64_t);
+ return setBuffersTimestamp(timestamp);
+}
+
+int Surface::dispatchLock(va_list args) {
+ ANativeWindow_Buffer* outBuffer = va_arg(args, ANativeWindow_Buffer*);
+ ARect* inOutDirtyBounds = va_arg(args, ARect*);
+ return lock(outBuffer, inOutDirtyBounds);
+}
+
+int Surface::dispatchUnlockAndPost(va_list args) {
+ return unlockAndPost();
+}
+
+
+int Surface::connect(int api) {
+ ATRACE_CALL();
+ ALOGV("Surface::connect");
+ Mutex::Autolock lock(mMutex);
+ IGraphicBufferProducer::QueueBufferOutput output;
+ int err = mGraphicBufferProducer->connect(api, &output);
+ if (err == NO_ERROR) {
+ uint32_t numPendingBuffers = 0;
+ output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint,
+ &numPendingBuffers);
+ mConsumerRunningBehind = (numPendingBuffers >= 2);
+ }
+ if (!err && api == NATIVE_WINDOW_API_CPU) {
+ mConnectedToCpu = true;
+ }
+ return err;
+}
+
+int Surface::disconnect(int api) {
+ ATRACE_CALL();
+ ALOGV("Surface::disconnect");
+ Mutex::Autolock lock(mMutex);
+ freeAllBuffers();
+ int err = mGraphicBufferProducer->disconnect(api);
+ if (!err) {
+ mReqFormat = 0;
+ mReqWidth = 0;
+ mReqHeight = 0;
+ mReqUsage = 0;
+ mCrop.clear();
+ mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
+ mTransform = 0;
+ if (api == NATIVE_WINDOW_API_CPU) {
+ mConnectedToCpu = false;
+ }
+ }
+ return err;
+}
+
+int Surface::setUsage(uint32_t reqUsage)
+{
+ ALOGV("Surface::setUsage");
+ Mutex::Autolock lock(mMutex);
+ mReqUsage = reqUsage;
+ return OK;
+}
+
+int Surface::setCrop(Rect const* rect)
+{
+ ATRACE_CALL();
+
+ Rect realRect;
+ if (rect == NULL || rect->isEmpty()) {
+ realRect.clear();
+ } else {
+ realRect = *rect;
}
- status_t err = SurfaceTextureClient::lock(&outBuffer, inOutDirtyBounds);
+ ALOGV("Surface::setCrop rect=[%d %d %d %d]",
+ realRect.left, realRect.top, realRect.right, realRect.bottom);
+
+ Mutex::Autolock lock(mMutex);
+ mCrop = realRect;
+ return NO_ERROR;
+}
+
+int Surface::setBufferCount(int bufferCount)
+{
+ ATRACE_CALL();
+ ALOGV("Surface::setBufferCount");
+ Mutex::Autolock lock(mMutex);
+
+ status_t err = mGraphicBufferProducer->setBufferCount(bufferCount);
+ ALOGE_IF(err, "IGraphicBufferProducer::setBufferCount(%d) returned %s",
+ bufferCount, strerror(-err));
if (err == NO_ERROR) {
- other->w = uint32_t(outBuffer.width);
- other->h = uint32_t(outBuffer.height);
- other->s = uint32_t(outBuffer.stride);
- other->usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
- other->format = uint32_t(outBuffer.format);
- other->bits = outBuffer.bits;
- }
-
- if (inOutDirtyRegion) {
- inOutDirtyRegion->set( static_cast<Rect const&>(temp) );
+ freeAllBuffers();
}
return err;
}
-status_t Surface::unlockAndPost() {
- return SurfaceTextureClient::unlockAndPost();
+int Surface::setBuffersDimensions(int w, int h)
+{
+ ATRACE_CALL();
+ ALOGV("Surface::setBuffersDimensions");
+
+ if (w<0 || h<0)
+ return BAD_VALUE;
+
+ if ((w && !h) || (!w && h))
+ return BAD_VALUE;
+
+ Mutex::Autolock lock(mMutex);
+ mReqWidth = w;
+ mReqHeight = h;
+ return NO_ERROR;
+}
+
+int Surface::setBuffersUserDimensions(int w, int h)
+{
+ ATRACE_CALL();
+ ALOGV("Surface::setBuffersUserDimensions");
+
+ if (w<0 || h<0)
+ return BAD_VALUE;
+
+ if ((w && !h) || (!w && h))
+ return BAD_VALUE;
+
+ Mutex::Autolock lock(mMutex);
+ mUserWidth = w;
+ mUserHeight = h;
+ return NO_ERROR;
+}
+
+int Surface::setBuffersFormat(int format)
+{
+ ALOGV("Surface::setBuffersFormat");
+
+ if (format<0)
+ return BAD_VALUE;
+
+ Mutex::Autolock lock(mMutex);
+ mReqFormat = format;
+ return NO_ERROR;
+}
+
+int Surface::setScalingMode(int mode)
+{
+ ATRACE_CALL();
+ ALOGV("Surface::setScalingMode(%d)", mode);
+
+ switch (mode) {
+ case NATIVE_WINDOW_SCALING_MODE_FREEZE:
+ case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
+ case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
+ break;
+ default:
+ ALOGE("unknown scaling mode: %d", mode);
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock lock(mMutex);
+ mScalingMode = mode;
+ return NO_ERROR;
+}
+
+int Surface::setBuffersTransform(int transform)
+{
+ ATRACE_CALL();
+ ALOGV("Surface::setBuffersTransform");
+ Mutex::Autolock lock(mMutex);
+ mTransform = transform;
+ return NO_ERROR;
+}
+
+int Surface::setBuffersTimestamp(int64_t timestamp)
+{
+ ALOGV("Surface::setBuffersTimestamp");
+ Mutex::Autolock lock(mMutex);
+ mTimestamp = timestamp;
+ return NO_ERROR;
+}
+
+void Surface::freeAllBuffers() {
+ for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+ mSlots[i].buffer = 0;
+ }
+}
+
+// ----------------------------------------------------------------------
+// the lock/unlock APIs must be used from the same thread
+
+static status_t copyBlt(
+ const sp<GraphicBuffer>& dst,
+ const sp<GraphicBuffer>& src,
+ const Region& reg)
+{
+ // src and dst with, height and format must be identical. no verification
+ // is done here.
+ status_t err;
+ uint8_t const * src_bits = NULL;
+ err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits);
+ ALOGE_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);
+ ALOGE_IF(err, "error locking dst buffer %s", strerror(-err));
+
+ Region::const_iterator head(reg.begin());
+ Region::const_iterator tail(reg.end());
+ if (head != tail && src_bits && dst_bits) {
+ const size_t bpp = bytesPerPixel(src->format);
+ const size_t dbpr = dst->stride * bpp;
+ const size_t sbpr = src->stride * bpp;
+
+ while (head != tail) {
+ const Rect& r(*head++);
+ ssize_t h = r.height();
+ if (h <= 0) continue;
+ size_t size = r.width() * bpp;
+ uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
+ uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
+ if (dbpr==sbpr && size==sbpr) {
+ size *= h;
+ h = 1;
+ }
+ do {
+ memcpy(d, s, size);
+ d += dbpr;
+ s += sbpr;
+ } while (--h > 0);
+ }
+ }
+
+ if (src_bits)
+ src->unlock();
+
+ if (dst_bits)
+ dst->unlock();
+
+ return err;
}
// ----------------------------------------------------------------------------
+
+status_t Surface::writeToParcel(
+ const sp<Surface>& surface, Parcel* parcel) {
+ sp<IGraphicBufferProducer> bp;
+ if (surface != NULL) {
+ bp = surface->mGraphicBufferProducer;
+ }
+ return parcel->writeStrongBinder(bp->asBinder());
+}
+
+sp<Surface> Surface::readFromParcel(const Parcel& data) {
+ sp<IBinder> binder(data.readStrongBinder());
+ sp<IGraphicBufferProducer> bp(interface_cast<IGraphicBufferProducer>(binder));
+ return new Surface(bp);
+}
+
+// ----------------------------------------------------------------------------
+
+status_t Surface::lock(
+ ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
+{
+ if (mLockedBuffer != 0) {
+ ALOGE("Surface::lock failed, already locked");
+ return INVALID_OPERATION;
+ }
+
+ if (!mConnectedToCpu) {
+ int err = Surface::connect(NATIVE_WINDOW_API_CPU);
+ if (err) {
+ return err;
+ }
+ // we're intending to do software rendering from this point
+ setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
+ }
+
+ ANativeWindowBuffer* out;
+ int fenceFd = -1;
+ status_t err = dequeueBuffer(&out, &fenceFd);
+ ALOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
+ if (err == NO_ERROR) {
+ sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
+ sp<Fence> fence(new Fence(fenceFd));
+
+ err = fence->waitForever(1000, "Surface::lock");
+ if (err != OK) {
+ ALOGE("Fence::wait failed (%s)", strerror(-err));
+ cancelBuffer(out, fenceFd);
+ return err;
+ }
+
+ const Rect bounds(backBuffer->width, backBuffer->height);
+
+ Region newDirtyRegion;
+ if (inOutDirtyBounds) {
+ newDirtyRegion.set(static_cast<Rect const&>(*inOutDirtyBounds));
+ newDirtyRegion.andSelf(bounds);
+ } else {
+ newDirtyRegion.set(bounds);
+ }
+
+ // figure out if we can copy the frontbuffer back
+ const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
+ const bool canCopyBack = (frontBuffer != 0 &&
+ backBuffer->width == frontBuffer->width &&
+ backBuffer->height == frontBuffer->height &&
+ backBuffer->format == frontBuffer->format);
+
+ if (canCopyBack) {
+ // copy the area that is invalid and not repainted this round
+ const Region copyback(mDirtyRegion.subtract(newDirtyRegion));
+ if (!copyback.isEmpty())
+ copyBlt(backBuffer, frontBuffer, copyback);
+ } else {
+ // if we can't copy-back anything, modify the user's dirty
+ // region to make sure they redraw the whole buffer
+ newDirtyRegion.set(bounds);
+ mDirtyRegion.clear();
+ Mutex::Autolock lock(mMutex);
+ for (size_t i=0 ; i<NUM_BUFFER_SLOTS ; i++) {
+ mSlots[i].dirtyRegion.clear();
+ }
+ }
+
+
+ { // scope for the lock
+ Mutex::Autolock lock(mMutex);
+ int backBufferSlot(getSlotFromBufferLocked(backBuffer.get()));
+ if (backBufferSlot >= 0) {
+ Region& dirtyRegion(mSlots[backBufferSlot].dirtyRegion);
+ mDirtyRegion.subtract(dirtyRegion);
+ dirtyRegion = newDirtyRegion;
+ }
+ }
+
+ mDirtyRegion.orSelf(newDirtyRegion);
+ if (inOutDirtyBounds) {
+ *inOutDirtyBounds = newDirtyRegion.getBounds();
+ }
+
+ void* vaddr;
+ status_t res = backBuffer->lock(
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ newDirtyRegion.bounds(), &vaddr);
+
+ ALOGW_IF(res, "failed locking buffer (handle = %p)",
+ backBuffer->handle);
+
+ if (res != 0) {
+ err = INVALID_OPERATION;
+ } else {
+ mLockedBuffer = backBuffer;
+ outBuffer->width = backBuffer->width;
+ outBuffer->height = backBuffer->height;
+ outBuffer->stride = backBuffer->stride;
+ outBuffer->format = backBuffer->format;
+ outBuffer->bits = vaddr;
+ }
+ }
+ return err;
+}
+
+status_t Surface::unlockAndPost()
+{
+ if (mLockedBuffer == 0) {
+ ALOGE("Surface::unlockAndPost failed, no locked buffer");
+ return INVALID_OPERATION;
+ }
+
+ status_t err = mLockedBuffer->unlock();
+ ALOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
+
+ err = queueBuffer(mLockedBuffer.get(), -1);
+ ALOGE_IF(err, "queueBuffer (handle=%p) failed (%s)",
+ mLockedBuffer->handle, strerror(-err));
+
+ mPostedBuffer = mLockedBuffer;
+ mLockedBuffer = 0;
+ return err;
+}
+
}; // namespace android