summaryrefslogtreecommitdiff
path: root/libs/gui/Surface.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/gui/Surface.cpp')
-rw-r--r--libs/gui/Surface.cpp92
1 files changed, 88 insertions, 4 deletions
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 6fc55c344e..42adf90840 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -44,7 +44,11 @@ Surface::Surface(
bool controlledByApp)
: mGraphicBufferProducer(bufferProducer),
mCrop(Rect::EMPTY_RECT),
- mGenerationNumber(0)
+ mGenerationNumber(0),
+ mSingleBufferMode(false),
+ mAutoRefresh(false),
+ mSharedBufferSlot(BufferItem::INVALID_BUFFER_SLOT),
+ mSharedBufferHasBeenQueued(false)
{
// Initialize the ANativeWindow function pointers.
ANativeWindow::setSwapInterval = hook_setSwapInterval;
@@ -232,6 +236,16 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
reqFormat = mReqFormat;
reqUsage = mReqUsage;
+
+ if (mSingleBufferMode && mAutoRefresh && mSharedBufferSlot !=
+ BufferItem::INVALID_BUFFER_SLOT) {
+ sp<GraphicBuffer>& gbuf(mSlots[mSharedBufferSlot].buffer);
+ if (gbuf != NULL) {
+ *buffer = gbuf.get();
+ *fenceFd = -1;
+ return OK;
+ }
+ }
} // Drop the lock so that we can still touch the Surface while blocking in IGBP::dequeueBuffer
int buf = -1;
@@ -279,6 +293,15 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
}
*buffer = gbuf.get();
+
+ if (mSingleBufferMode && mAutoRefresh) {
+ mSharedBufferSlot = buf;
+ mSharedBufferHasBeenQueued = false;
+ } else if (mSharedBufferSlot == buf) {
+ mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT;
+ mSharedBufferHasBeenQueued = false;
+ }
+
return OK;
}
@@ -294,8 +317,19 @@ int Surface::cancelBuffer(android_native_buffer_t* buffer,
}
return i;
}
+ if (mSharedBufferSlot == i && mSharedBufferHasBeenQueued) {
+ if (fenceFd >= 0) {
+ close(fenceFd);
+ }
+ return OK;
+ }
sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
mGraphicBufferProducer->cancelBuffer(i, fence);
+
+ if (mSingleBufferMode && mAutoRefresh && mSharedBufferSlot == i) {
+ mSharedBufferHasBeenQueued = true;
+ }
+
return OK;
}
@@ -323,6 +357,7 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {
Mutex::Autolock lock(mMutex);
int64_t timestamp;
bool isAutoTimestamp = false;
+
if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) {
timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
isAutoTimestamp = true;
@@ -338,6 +373,12 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {
}
return i;
}
+ if (mSharedBufferSlot == i && mSharedBufferHasBeenQueued) {
+ if (fenceFd >= 0) {
+ close(fenceFd);
+ }
+ return OK;
+ }
// Make sure the crop rectangle is entirely inside the buffer.
@@ -417,6 +458,7 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {
if (err != OK) {
ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err);
}
+
uint32_t numPendingBuffers = 0;
uint32_t hint = 0;
output.deflate(&mDefaultWidth, &mDefaultHeight, &hint,
@@ -434,6 +476,10 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {
mDirtyRegion = Region::INVALID_REGION;
}
+ if (mSingleBufferMode && mAutoRefresh && mSharedBufferSlot == i) {
+ mSharedBufferHasBeenQueued = true;
+ }
+
return err;
}
@@ -557,6 +603,9 @@ int Surface::perform(int operation, va_list args)
case NATIVE_WINDOW_SET_SINGLE_BUFFER_MODE:
res = dispatchSetSingleBufferMode(args);
break;
+ case NATIVE_WINDOW_SET_AUTO_REFRESH:
+ res = dispatchSetAutoRefresh(args);
+ break;
default:
res = NAME_NOT_FOUND;
break;
@@ -669,8 +718,12 @@ int Surface::dispatchSetSurfaceDamage(va_list args) {
int Surface::dispatchSetSingleBufferMode(va_list args) {
bool singleBufferMode = va_arg(args, int);
- setSingleBufferMode(singleBufferMode);
- return NO_ERROR;
+ return setSingleBufferMode(singleBufferMode);
+}
+
+int Surface::dispatchSetAutoRefresh(va_list args) {
+ bool autoRefresh = va_arg(args, int);
+ return setAutoRefresh(autoRefresh);
}
int Surface::connect(int api) {
@@ -714,6 +767,8 @@ int Surface::disconnect(int api) {
ATRACE_CALL();
ALOGV("Surface::disconnect");
Mutex::Autolock lock(mMutex);
+ mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT;
+ mSharedBufferHasBeenQueued = false;
freeAllBuffers();
int err = mGraphicBufferProducer->disconnect(api);
if (!err) {
@@ -796,6 +851,9 @@ int Surface::setUsage(uint32_t reqUsage)
{
ALOGV("Surface::setUsage");
Mutex::Autolock lock(mMutex);
+ if (reqUsage != mReqUsage) {
+ mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT;
+ }
mReqUsage = reqUsage;
return OK;
}
@@ -888,12 +946,29 @@ int Surface::setSingleBufferMode(bool singleBufferMode) {
status_t err = mGraphicBufferProducer->setSingleBufferMode(
singleBufferMode);
- ALOGE_IF(err, "IGraphicsBufferProducer::setSingleBufferMode(%d) returned"
+ if (err == NO_ERROR) {
+ mSingleBufferMode = singleBufferMode;
+ }
+ ALOGE_IF(err, "IGraphicBufferProducer::setSingleBufferMode(%d) returned"
"%s", singleBufferMode, strerror(-err));
return err;
}
+int Surface::setAutoRefresh(bool autoRefresh) {
+ ATRACE_CALL();
+ ALOGV("Surface::setAutoRefresh (%d)", autoRefresh);
+ Mutex::Autolock lock(mMutex);
+
+ status_t err = mGraphicBufferProducer->setAutoRefresh(autoRefresh);
+ if (err == NO_ERROR) {
+ mAutoRefresh = autoRefresh;
+ }
+ ALOGE_IF(err, "IGraphicBufferProducer::setAutoRefresh(%d) returned %s",
+ autoRefresh, strerror(-err));
+ return err;
+}
+
int Surface::setBuffersDimensions(uint32_t width, uint32_t height)
{
ATRACE_CALL();
@@ -903,6 +978,9 @@ int Surface::setBuffersDimensions(uint32_t width, uint32_t height)
return BAD_VALUE;
Mutex::Autolock lock(mMutex);
+ if (width != mReqWidth || height != mReqHeight) {
+ mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT;
+ }
mReqWidth = width;
mReqHeight = height;
return NO_ERROR;
@@ -917,6 +995,9 @@ int Surface::setBuffersUserDimensions(uint32_t width, uint32_t height)
return BAD_VALUE;
Mutex::Autolock lock(mMutex);
+ if (width != mUserWidth || height != mUserHeight) {
+ mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT;
+ }
mUserWidth = width;
mUserHeight = height;
return NO_ERROR;
@@ -927,6 +1008,9 @@ int Surface::setBuffersFormat(PixelFormat format)
ALOGV("Surface::setBuffersFormat");
Mutex::Autolock lock(mMutex);
+ if (format != mReqFormat) {
+ mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT;
+ }
mReqFormat = format;
return NO_ERROR;
}