From bbef29560e318cbdb0d4107b7fce6a2a64fd641b Mon Sep 17 00:00:00 2001 From: Ramkumar Radhakrishnan Date: Tue, 6 Nov 2012 20:44:04 -0800 Subject: libgui: Add support to update buffer geometry. Add native window properties NATIVE_WINDOW_UPDATE_BUFFERS_GEOMETRY to the perform function of SurfaceTextureClient and SurfaceTexture to update the width, height and format of the buffer dynamically from the client before queue buffer call. Change-Id: I62447fcf523b507d534085cd0835f55a978c4ead --- include/gui/BufferQueue.h | 27 ++++++++ include/gui/ISurfaceTexture.h | 4 ++ include/gui/SurfaceTextureClient.h | 2 + include/ui/GraphicBuffer.h | 4 ++ include/ui/GraphicBufferMapper.h | 5 ++ libs/gui/BufferQueue.cpp | 122 +++++++++++++++++++++++++++++++++++++ libs/gui/ISurfaceTexture.cpp | 25 ++++++++ libs/gui/SurfaceTextureClient.cpp | 26 ++++++++ libs/ui/GraphicBuffer.cpp | 10 +++ libs/ui/GraphicBufferMapper.cpp | 13 ++++ 10 files changed, 238 insertions(+) diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h index 02598b0..cd38cfe 100644 --- a/include/gui/BufferQueue.h +++ b/include/gui/BufferQueue.h @@ -33,6 +33,23 @@ namespace android { // ---------------------------------------------------------------------------- +#ifdef QCOM_BSP +/* + * Structure to hold the buffer geometry + */ +struct QBufGeometry { + int mWidth; + int mHeight; + int mFormat; + QBufGeometry(): mWidth(0), mHeight(0), mFormat(0) {} + void set(int w, int h, int f) { + mWidth = w; + mHeight = h; + mFormat = f; + } +}; +#endif + class BufferQueue : public BnSurfaceTexture { public: enum { MIN_UNDEQUEUED_BUFFERS = 2 }; @@ -156,6 +173,11 @@ public: // to calculate the size for the buffer. this will take effect from next // dequeue buffer. virtual status_t setBuffersSize(int size); + + // update buffer width, height and format for a native buffer + // dynamically from the client which will take effect in the next + // queue buffer. + virtual status_t updateBuffersGeometry(int w, int h, int f); #endif // connect attempts to connect a producer client API to the BufferQueue. @@ -547,6 +569,11 @@ private: // mTransformHint is used to optimize for screen rotations uint32_t mTransformHint; + +#ifdef QCOM_BSP + // holds the updated buffer geometry info of the new video resolution. + QBufGeometry mNextBufferInfo; +#endif }; // ---------------------------------------------------------------------------- diff --git a/include/gui/ISurfaceTexture.h b/include/gui/ISurfaceTexture.h index f0beab6..f2a6510 100644 --- a/include/gui/ISurfaceTexture.h +++ b/include/gui/ISurfaceTexture.h @@ -172,6 +172,10 @@ public: // calculate the size for the buffer. this will take effect from next // dequeue buffer. virtual status_t setBuffersSize(int size) = 0; + + // update buffer width, height and format information from the client + // which will take effect in the next queue buffer. + virtual status_t updateBuffersGeometry(int w, int h, int f) = 0; #endif // connect attempts to connect a client API to the SurfaceTexture. This diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h index 108126d..f2b523d 100644 --- a/include/gui/SurfaceTextureClient.h +++ b/include/gui/SurfaceTextureClient.h @@ -94,6 +94,7 @@ private: int dispatchSetPostTransformCrop(va_list args); int dispatchSetUsage(va_list args); #ifdef QCOM_BSP + int dispatchUpdateBuffersGeometry(va_list args); int dispatchSetBuffersSize(va_list args); #endif int dispatchLock(va_list args); @@ -107,6 +108,7 @@ protected: virtual int query(int what, int* value) const; virtual int setSwapInterval(int interval); #ifdef QCOM_BSP + virtual int updateBuffersGeometry(int w, int h, int f); virtual int setBuffersSize(int size); #endif virtual int lockBuffer_DEPRECATED(ANativeWindowBuffer* buffer); diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h index 60bbf18..af85063 100644 --- a/include/ui/GraphicBuffer.h +++ b/include/ui/GraphicBuffer.h @@ -103,6 +103,10 @@ public: status_t lock(uint32_t usage, void** vaddr); status_t lock(uint32_t usage, const Rect& rect, void** vaddr); status_t unlock(); +#ifdef QCOM_BSP + status_t perform(buffer_handle_t hnd, int operation, + uint32_t w, uint32_t h, PixelFormat format); +#endif ANativeWindowBuffer* getNativeBuffer() const; diff --git a/include/ui/GraphicBufferMapper.h b/include/ui/GraphicBufferMapper.h index 1fdecab..858fb1b 100644 --- a/include/ui/GraphicBufferMapper.h +++ b/include/ui/GraphicBufferMapper.h @@ -51,6 +51,11 @@ public: status_t getphys(buffer_handle_t handle, void** paddr); #endif +#ifdef QCOM_BSP + status_t perform(buffer_handle_t handle, int operation, + uint32_t w, uint32_t h, uint32_t format); +#endif + // dumps information about the mapping of this handle void dump(buffer_handle_t handle); diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 5226037..acf6cec 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -64,6 +64,70 @@ static const char* scalingModeName(int scalingMode) { } } +#ifdef QCOM_BSP +/* + * Checks if memory needs to be reallocated for this buffer. + * + * @param: Geometry of the current buffer. + * @param: Required Geometry. + * @param: Geometry of the updated buffer. + * + * @return True if a memory reallocation is required. + */ +static bool needNewBuffer(const QBufGeometry currentGeometry, + const QBufGeometry requiredGeometry, + const QBufGeometry updatedGeometry) +{ + // no allocation required if there is change in resoultion or format. + if (updatedGeometry.mWidth && updatedGeometry.mHeight && + updatedGeometry.mFormat) { + return false; + } + // If the current buffer info matches the updated info, + // we do not require any memory allocation. + if (currentGeometry.mWidth != requiredGeometry.mWidth || + currentGeometry.mHeight != requiredGeometry.mHeight || + currentGeometry.mFormat != requiredGeometry.mFormat) { + // Current and required geometry do not match. Allocation + // required. + return true; + } + return false; +} + +/* + * Geometry update for the currently queued buffer is required or not. + * + * @param: buffer currently queued buffer. + * @param: Updated width + * @param: Updated height + * @param: Updated format + * + * @return True if a buffer needs to be updated with new attributes. + */ +static bool isBufferGeometryUpdateRequired(sp buffer, + const QBufGeometry updatedGeometry) +{ + if (buffer == 0) { + ALOGW("isBufferGeometryUpdateRequired: graphic buffer is NULL"); + return false; + } + + if (!updatedGeometry.mWidth || !updatedGeometry.mHeight || + !updatedGeometry.mFormat) { + // No update required. Return. + return false; + } + if (buffer->width == updatedGeometry.mWidth && + buffer->height == updatedGeometry.mHeight && + buffer->format == updatedGeometry.mFormat) { + // The buffer has already been updated. Return. + return false; + } + return true; +} +#endif + BufferQueue::BufferQueue(bool allowSynchronousMode, const sp& allocator) : mDefaultWidth(1), @@ -94,6 +158,9 @@ BufferQueue::BufferQueue(bool allowSynchronousMode, } else { mGraphicBufferAlloc = allocator; } +#ifdef QCOM_BSP + mNextBufferInfo.set(0, 0, 0); +#endif } BufferQueue::~BufferQueue() { @@ -387,10 +454,29 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp& outFence, mSlots[buf].mBufferState = BufferSlot::DEQUEUED; const sp& buffer(mSlots[buf].mGraphicBuffer); +#ifdef QCOM_BSP + QBufGeometry currentGeometry; + if (buffer != NULL) + currentGeometry.set(buffer->width, buffer->height, buffer->format); + else + currentGeometry.set(0, 0, 0); + + QBufGeometry requiredGeometry; + requiredGeometry.set(w, h, format); + + QBufGeometry updatedGeometry; + updatedGeometry.set(mNextBufferInfo.mWidth, mNextBufferInfo.mHeight, + mNextBufferInfo.mFormat); +#endif + if ((buffer == NULL) || +#ifdef QCOM_BSP + needNewBuffer(currentGeometry, requiredGeometry, updatedGeometry) || +#else (uint32_t(buffer->width) != w) || (uint32_t(buffer->height) != h) || (uint32_t(buffer->format) != format) || +#endif ((uint32_t(buffer->usage) & usage) != usage)) { mSlots[buf].mAcquireCalled = false; @@ -453,6 +539,15 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp& outFence, return returnFlags; } +#ifdef QCOM_BSP +status_t BufferQueue::updateBuffersGeometry(int w, int h, int f) { + ST_LOGV("updateBuffersGeometry: w=%d h=%d f=%d", w, h, f); + Mutex::Autolock lock(mMutex); + mNextBufferInfo.set(w, h, f); + return NO_ERROR; +} +#endif + status_t BufferQueue::setSynchronousMode(bool enabled) { ATRACE_CALL(); ST_LOGV("setSynchronousMode: enabled=%d", enabled); @@ -526,7 +621,31 @@ status_t BufferQueue::queueBuffer(int buf, return -EINVAL; } +#ifdef QCOM_BSP + // Update the buffer Geometry if required + QBufGeometry updatedGeometry; + updatedGeometry.set(mNextBufferInfo.mWidth, + mNextBufferInfo.mHeight, mNextBufferInfo.mFormat); +#endif const sp& graphicBuffer(mSlots[buf].mGraphicBuffer); +#ifdef QCOM_BSP + // Update the geometry of this buffer without reallocation. + if(isBufferGeometryUpdateRequired(graphicBuffer, updatedGeometry)) { + status_t res = graphicBuffer->perform(graphicBuffer->handle, + GRALLOC_MODULE_PERFORM_UPDATE_BUFFER_GEOMETRY, + updatedGeometry.mWidth, + updatedGeometry.mHeight, + updatedGeometry.mFormat); + if(res == NO_ERROR) { + graphicBuffer->width = updatedGeometry.mWidth; + graphicBuffer->height = updatedGeometry.mHeight; + graphicBuffer->format = updatedGeometry.mFormat; + // set flags to destroy old eglImage and create new eglImage. + mSlots[buf].mAcquireCalled = false; + mSlots[buf].mEglDisplay = EGL_NO_DISPLAY; + } + } +#endif Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight()); Rect croppedCrop; crop.intersect(bufferRect, &croppedCrop); @@ -691,6 +810,9 @@ status_t BufferQueue::disconnect(int api) { if (mConnectedApi == api) { drainQueueAndFreeBuffersLocked(); mConnectedApi = NO_CONNECTED_API; +#ifdef QCOM_BSP + mNextBufferInfo.set(0, 0, 0); +#endif mDequeueCondition.broadcast(); listener = mConsumerListener; } else { diff --git a/libs/gui/ISurfaceTexture.cpp b/libs/gui/ISurfaceTexture.cpp index 4b20a36..ce31a5b 100644 --- a/libs/gui/ISurfaceTexture.cpp +++ b/libs/gui/ISurfaceTexture.cpp @@ -39,6 +39,7 @@ enum { QUERY, SET_SYNCHRONOUS_MODE, #ifdef QCOM_BSP + UPDATE_BUFFERS_GEOMETRY, SET_BUFFERS_SIZE, #endif CONNECT, @@ -160,6 +161,21 @@ public: } #ifdef QCOM_BSP + virtual status_t updateBuffersGeometry(int w, int h, int f) { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); + data.writeInt32(w); + data.writeInt32(h); + data.writeInt32(f); + status_t result = remote()->transact(UPDATE_BUFFERS_GEOMETRY, + data, &reply); + if (result != NO_ERROR) { + return result; + } + result = reply.readInt32(); + return result; + } + virtual status_t setBuffersSize(int size) { Parcel data, reply; data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); @@ -284,6 +300,15 @@ status_t BnSurfaceTexture::onTransact( return NO_ERROR; } break; #ifdef QCOM_BSP + case UPDATE_BUFFERS_GEOMETRY: { + CHECK_INTERFACE(ISurfaceTexture, data, reply); + int w = data.readInt32(); + int h = data.readInt32(); + int f = data.readInt32(); + status_t res = updateBuffersGeometry(w, h, f); + reply->writeInt32(res); + return NO_ERROR; + } break; case SET_BUFFERS_SIZE: { CHECK_INTERFACE(ISurfaceTexture, data, reply); int size = data.readInt32(); diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp index e33b026..5de963c 100644 --- a/libs/gui/SurfaceTextureClient.cpp +++ b/libs/gui/SurfaceTextureClient.cpp @@ -407,6 +407,9 @@ int SurfaceTextureClient::perform(int operation, va_list args) case NATIVE_WINDOW_SET_BUFFERS_SIZE: res = dispatchSetBuffersSize(args); break; + case NATIVE_WINDOW_UPDATE_BUFFERS_GEOMETRY: + res = dispatchUpdateBuffersGeometry(args); + break; #endif case NATIVE_WINDOW_LOCK: res = dispatchLock(args); @@ -490,6 +493,13 @@ int SurfaceTextureClient::dispatchSetBuffersSize(va_list args) { int size = va_arg(args, int); return setBuffersSize(size); } + +int SurfaceTextureClient::dispatchUpdateBuffersGeometry(va_list args) { + int w = va_arg(args, int); + int h = va_arg(args, int); + int f = va_arg(args, int); + return updateBuffersGeometry(w, h, f); +} #endif int SurfaceTextureClient::dispatchSetScalingMode(va_list args) { @@ -666,6 +676,22 @@ int SurfaceTextureClient::setBuffersSize(int size) } return NO_ERROR; } + +int SurfaceTextureClient::updateBuffersGeometry(int w, int h, int f) +{ + ATRACE_CALL(); + ALOGV("SurfaceTextureClient::updateBuffersGeometry"); + + if (w<0 || h<0 || f<0) + return BAD_VALUE; + + if ((w && !h) || (!w && h)) + return BAD_VALUE; + + Mutex::Autolock lock(mMutex); + status_t err = mSurfaceTexture->updateBuffersGeometry(w, h, f); + return err; +} #endif int SurfaceTextureClient::setScalingMode(int mode) diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp index b447d00..219375e 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -213,6 +213,16 @@ status_t GraphicBuffer::unlock() return res; } +#ifdef QCOM_BSP +status_t GraphicBuffer::perform(buffer_handle_t hnd, int operation, + uint32_t w, uint32_t h, PixelFormat format) +{ + status_t res = getBufferMapper().perform(hnd, + GRALLOC_MODULE_PERFORM_UPDATE_BUFFER_GEOMETRY, w, h, format); + return res; +} +#endif + size_t GraphicBuffer::getFlattenedSize() const { return (8 + (handle ? handle->numInts : 0))*sizeof(int); } diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp index 19c549d..d16a1bb 100644 --- a/libs/ui/GraphicBufferMapper.cpp +++ b/libs/ui/GraphicBufferMapper.cpp @@ -108,5 +108,18 @@ status_t GraphicBufferMapper::getphys(buffer_handle_t handle, void** paddr) } #endif +#ifdef QCOM_BSP +status_t GraphicBufferMapper::perform(buffer_handle_t handle, int operation, + uint32_t w, uint32_t h, uint32_t format) +{ + ATRACE_CALL(); + status_t err; + + err = mAllocMod->perform(mAllocMod, operation, w, h, format, handle); + + ALOGW_IF(err, "perform(...) failed %d (%s)", err, strerror(-err)); + return err; +} +#endif // --------------------------------------------------------------------------- }; // namespace android -- cgit v1.1