Permalink
Browse files

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
  • Loading branch information...
1 parent d88381f commit 4aa497ae53b91f50cf83738be10d45a4046477da Ramkumar Radhakrishnan committed with xoomdev Aug 30, 2012
@@ -32,6 +32,22 @@
namespace android {
// ----------------------------------------------------------------------------
+#ifdef QCOM_HARDWARE
+/*
+ * Structure to hold the buffer geometry
+ */
+struct qBufGeometry {
+ int width;
+ int height;
+ int format;
+ void set(int w, int h, int f) {
+ width = w;
+ height = h;
+ format = f;
+ }
+};
+#endif
+
class BufferQueue : public BnSurfaceTexture {
public:
enum { MIN_UNDEQUEUED_BUFFERS = 2 };
@@ -143,6 +159,11 @@ class BufferQueue : public BnSurfaceTexture {
// for interlaced use cases where the user can pass extra information about
// the type of the frame whether it is interlaced or progressive frame.
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.
@@ -177,7 +198,7 @@ class BufferQueue : public BnSurfaceTexture {
mTimestamp(0),
mFrameNumber(0),
mBuf(INVALID_BUFFER_SLOT) {
- mCrop.makeInvalid();
+ mCrop.makeInvalid();
}
// mGraphicBuffer points to the buffer allocated for this slot or is NULL
// if no buffer has been allocated.
@@ -201,7 +222,7 @@ class BufferQueue : public BnSurfaceTexture {
// mBuf is the slot index of this buffer
int mBuf;
- };
+ };
// The following public functions is the consumer facing interface
@@ -490,8 +511,11 @@ class BufferQueue : public BnSurfaceTexture {
// mTransformHint is used to optimize for screen rotations
uint32_t mTransformHint;
-};
+#ifdef QCOM_HARDWARE
+ qBufGeometry mNextBufferInfo;
+#endif
+};
// ----------------------------------------------------------------------------
}; // namespace android
@@ -154,6 +154,10 @@ class ISurfaceTexture : public IInterface
// for interlaced use cases where the user can pass extra information about
// the type of the frame whether it is interlaced or progressive frame.
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
@@ -84,6 +84,7 @@ class SurfaceTextureClient
int dispatchSetUsage(va_list args);
#ifdef QCOM_HARDWARE
int dispatchSetBuffersSize(va_list args);
+ int dispatchUpdateBuffersGeometry(va_list args);
#endif
int dispatchLock(va_list args);
int dispatchUnlockAndPost(va_list args);
@@ -98,6 +99,7 @@ class SurfaceTextureClient
virtual int setSwapInterval(int interval);
#ifdef QCOM_HARDWARE
virtual int setBuffersSize(int size);
+ virtual int updateBuffersGeometry(int w, int h, int f);
#endif
virtual int connect(int api);
@@ -31,6 +31,9 @@
#include <utils/Log.h>
#include <gui/SurfaceTexture.h>
#include <utils/Trace.h>
+#ifdef QCOM_HARDWARE
+#include <gralloc_priv.h>
+#endif // QCOM_HARDWARE
// This compile option causes SurfaceTexture to return the buffer that is currently
// attached to the GL texture from dequeueBuffer when no other buffers are
@@ -81,6 +84,83 @@ static const char* scalingModeName(int scalingMode) {
}
}
+#ifdef QCOM_HARDWARE
+/*
+ * 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.
+ */
+bool needNewBuffer(const qBufGeometry currentGeometry,
+ const qBufGeometry requiredGeometry,
+ const qBufGeometry updatedGeometry)
+{
+ // If the current buffer info matches the updated info,
+ // we do not require any memory allocation.
+ if (updatedGeometry.width && updatedGeometry.height &&
+ updatedGeometry.format) {
+ return false;
+ }
+ if (currentGeometry.width != requiredGeometry.width ||
+ currentGeometry.height != requiredGeometry.height ||
+ currentGeometry.format != requiredGeometry.format) {
+ // Current and required geometry do not match. Allocation
+ // required.
+ return true;
+ }
+ return false;
+}
+
+/*
+ * Update the geometry of this buffer without reallocation.
+ *
+ * @param: buffer whose geometry needs to be updated.
+ * @param: Updated width
+ * @param: Updated height
+ * @param: Updated format
+ */
+int updateBufferGeometry(sp<GraphicBuffer> buffer, const qBufGeometry updatedGeometry)
+{
+ if (buffer == 0) {
+ ALOGE("updateBufferGeometry: graphic buffer is NULL");
+ return -EINVAL;
+ }
+
+ if (!updatedGeometry.width || !updatedGeometry.height ||
+ !updatedGeometry.format) {
+ // No update required. Return.
+ return 0;
+ }
+ if (buffer->width == updatedGeometry.width &&
+ buffer->height == updatedGeometry.height &&
+ buffer->format == updatedGeometry.format) {
+ // The buffer has already been updated. Return.
+ return 0;
+ }
+ // Validate the handle
+ if (private_handle_t::validate(buffer->handle)) {
+ ALOGE("updateBufferGeometry: handle is invalid");
+ return -EINVAL;
+ }
+ buffer->width = updatedGeometry.width;
+ buffer->height = updatedGeometry.height;
+ buffer->format = updatedGeometry.format;
+ private_handle_t *hnd = (private_handle_t*)(buffer->handle);
+ if (hnd) {
+ hnd->width = updatedGeometry.width;
+ hnd->height = updatedGeometry.height;
+ hnd->format = updatedGeometry.format;
+ } else {
+ ALOGE("updateBufferGeometry: hnd is NULL");
+ return -EINVAL;
+ }
+ return 0;
+}
+#endif
+
BufferQueue::BufferQueue( bool allowSynchronousMode, int bufferCount ) :
mDefaultWidth(1),
mDefaultHeight(1),
@@ -110,6 +190,9 @@ BufferQueue::BufferQueue( bool allowSynchronousMode, int bufferCount ) :
if (mGraphicBufferAlloc == 0) {
ST_LOGE("createGraphicBufferAlloc() failed in BufferQueue()");
}
+#ifdef QCOM_HARDWARE
+ mNextBufferInfo.set(0, 0, 0);
+#endif
}
BufferQueue::~BufferQueue() {
@@ -459,16 +542,38 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
// keep the current (or default) format
format = mPixelFormat;
}
-
+#ifdef QCOM_HARDWARE
+ const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer);
+#endif
// buffer is now in DEQUEUED (but can also be current at the same time,
// if we're in synchronous mode)
mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
+#ifdef QCOM_HARDWARE
+ 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.width, mNextBufferInfo.height,
+ mNextBufferInfo.format);
+#endif
+#ifndef QCOM_HARDWARE
const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer);
+#endif
if ((buffer == NULL) ||
+#ifndef QCOM_HARDWARE
(uint32_t(buffer->width) != w) ||
(uint32_t(buffer->height) != h) ||
(uint32_t(buffer->format) != format) ||
+#else
+ needNewBuffer(currentGeometry, requiredGeometry, updatedGeometry) ||
+#endif
((uint32_t(buffer->usage) & usage) != usage))
{
status_t error;
@@ -517,6 +622,15 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
return returnFlags;
}
+#ifdef QCOM_HARDWARE
+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);
@@ -588,6 +702,14 @@ status_t BufferQueue::queueBuffer(int buf,
return -EINVAL;
}
+#ifdef QCOM_HARDWARE
+ // Update the buffer Geometry if required
+ qBufGeometry updatedGeometry;
+ updatedGeometry.set(mNextBufferInfo.width,
+ mNextBufferInfo.height, mNextBufferInfo.format);
+ updateBufferGeometry(mSlots[buf].mGraphicBuffer, updatedGeometry);
+#endif
+
const sp<GraphicBuffer>& graphicBuffer(mSlots[buf].mGraphicBuffer);
Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight());
Rect croppedCrop;
@@ -748,6 +870,9 @@ status_t BufferQueue::disconnect(int api) {
if (mConnectedApi == api) {
drainQueueAndFreeBuffersLocked();
mConnectedApi = NO_CONNECTED_API;
+#ifdef QCOM_HARDWARE
+ mNextBufferInfo.set(0, 0, 0);
+#endif
mDequeueCondition.broadcast();
listener = mConsumerListener;
} else {
@@ -40,6 +40,7 @@ enum {
SET_SYNCHRONOUS_MODE,
#ifdef QCOM_HARDWARE
SET_BUFFERS_SIZE,
+ UPDATE_BUFFERS_GEOMETRY,
#endif
CONNECT,
DISCONNECT,
@@ -160,6 +161,20 @@ class BpSurfaceTexture : public BpInterface<ISurfaceTexture>
result = reply.readInt32();
return result;
}
+
+ 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;
+ }
#endif
virtual status_t connect(int api, QueueBufferOutput* output) {
@@ -270,6 +285,15 @@ status_t BnSurfaceTexture::onTransact(
reply->writeInt32(res);
return NO_ERROR;
} break;
+ 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;
#endif
case CONNECT: {
CHECK_INTERFACE(ISurfaceTexture, data, reply);
@@ -353,6 +353,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);
@@ -434,6 +437,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) {
@@ -624,6 +634,22 @@ int SurfaceTextureClient::setBuffersSize(int size)
status_t err = mSurfaceTexture->setBuffersSize(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 NO_ERROR;
+}
#endif
int SurfaceTextureClient::setScalingMode(int mode)

0 comments on commit 4aa497a

Please sign in to comment.