From 1681d95989271f3a9ac0dbb93d10e4a29f2b4444 Mon Sep 17 00:00:00 2001 From: Ruben Brunk Date: Fri, 27 Jun 2014 15:51:55 -0700 Subject: [PATCH] Add sticky transform to surfaceflinger. Bug: 15116722 - Adds a sticky transform field that can be set from a SurfaceFlinger client Surface. This transform is added to any transform applied to the Surface. Change-Id: Idaa4311dfd027b2d2b8ea5e2c6cba2da5779d753 --- include/gui/BufferQueueProducer.h | 2 ++ include/gui/IGraphicBufferProducer.h | 15 ++++++++--- include/gui/Surface.h | 8 ++++++ libs/gui/BufferQueueProducer.cpp | 11 ++++++-- libs/gui/IGraphicBufferProducer.cpp | 4 +++ libs/gui/Surface.cpp | 40 +++++++++++++++++++++++++--- services/surfaceflinger/Layer.cpp | 27 ++++++++++++++----- services/surfaceflinger/Layer.h | 3 +++ 8 files changed, 94 insertions(+), 16 deletions(-) diff --git a/include/gui/BufferQueueProducer.h b/include/gui/BufferQueueProducer.h index fe8a30896..3fc5de2dd 100644 --- a/include/gui/BufferQueueProducer.h +++ b/include/gui/BufferQueueProducer.h @@ -195,6 +195,8 @@ private: // most updates). String8 mConsumerName; + uint32_t mStickyTransform; + }; // class BufferQueueProducer } // namespace android diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h index 9b96b2b84..4e9e81070 100644 --- a/include/gui/IGraphicBufferProducer.h +++ b/include/gui/IGraphicBufferProducer.h @@ -273,15 +273,18 @@ public: // async - if the buffer is queued in asynchronous mode // fence - a fence that the consumer must wait on before reading the buffer, // set this to Fence::NO_FENCE if the buffer is ready immediately + // sticky - the sticky transform set in Surface (only used by the LEGACY + // camera mode). inline QueueBufferInput(int64_t timestamp, bool isAutoTimestamp, const Rect& crop, int scalingMode, uint32_t transform, bool async, - const sp& fence) + const sp& fence, uint32_t sticky = 0) : timestamp(timestamp), isAutoTimestamp(isAutoTimestamp), crop(crop), - scalingMode(scalingMode), transform(transform), async(async), - fence(fence) { } + scalingMode(scalingMode), transform(transform), stickyTransform(sticky), + async(async), fence(fence) { } inline void deflate(int64_t* outTimestamp, bool* outIsAutoTimestamp, Rect* outCrop, int* outScalingMode, uint32_t* outTransform, - bool* outAsync, sp* outFence) const { + bool* outAsync, sp* outFence, + uint32_t* outStickyTransform = NULL) const { *outTimestamp = timestamp; *outIsAutoTimestamp = bool(isAutoTimestamp); *outCrop = crop; @@ -289,6 +292,9 @@ public: *outTransform = transform; *outAsync = bool(async); *outFence = fence; + if (outStickyTransform != NULL) { + *outStickyTransform = stickyTransform; + } } // Flattenable protocol @@ -303,6 +309,7 @@ public: Rect crop; int scalingMode; uint32_t transform; + uint32_t stickyTransform; int async; sp fence; }; diff --git a/include/gui/Surface.h b/include/gui/Surface.h index dcfe74f45..35ab7f618 100644 --- a/include/gui/Surface.h +++ b/include/gui/Surface.h @@ -138,6 +138,7 @@ private: int dispatchSetBuffersFormat(va_list args); int dispatchSetScalingMode(va_list args); int dispatchSetBuffersTransform(va_list args); + int dispatchSetBuffersStickyTransform(va_list args); int dispatchSetBuffersTimestamp(va_list args); int dispatchSetCrop(va_list args); int dispatchSetPostTransformCrop(va_list args); @@ -163,6 +164,7 @@ protected: virtual int setBuffersFormat(int format); virtual int setScalingMode(int mode); virtual int setBuffersTransform(int transform); + virtual int setBuffersStickyTransform(int transform); virtual int setBuffersTimestamp(int64_t timestamp); virtual int setCrop(Rect const* rect); virtual int setUsage(uint32_t reqUsage); @@ -231,6 +233,12 @@ private: // buffer that gets queued. It is set by calling setTransform. uint32_t mTransform; + // mStickyTransform is a transform that is applied on top of mTransform + // in each buffer that is queued. This is typically used to force the + // compositor to apply a transform, and will prevent the transform hint + // from being set by the compositor. + uint32_t mStickyTransform; + // mDefaultWidth is default width of the buffers, regardless of the // native_window_set_buffers_dimensions call. uint32_t mDefaultWidth; diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 70c3ff33e..6feebf72c 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -37,7 +37,8 @@ namespace android { BufferQueueProducer::BufferQueueProducer(const sp& core) : mCore(core), mSlots(core->mSlots), - mConsumerName() {} + mConsumerName(), + mStickyTransform(0) {} BufferQueueProducer::~BufferQueueProducer() {} @@ -509,10 +510,11 @@ status_t BufferQueueProducer::queueBuffer(int slot, Rect crop; int scalingMode; uint32_t transform; + uint32_t stickyTransform; bool async; sp fence; input.deflate(×tamp, &isAutoTimestamp, &crop, &scalingMode, &transform, - &async, &fence); + &async, &fence, &stickyTransform); if (fence == NULL) { BQ_LOGE("queueBuffer: fence is NULL"); @@ -601,6 +603,8 @@ status_t BufferQueueProducer::queueBuffer(int slot, item.mFence = fence; item.mIsDroppable = mCore->mDequeueBufferCannotBlock || async; + mStickyTransform = stickyTransform; + if (mCore->mQueue.empty()) { // When the queue is empty, we can ignore mDequeueBufferCannotBlock // and simply queue this buffer @@ -701,6 +705,9 @@ int BufferQueueProducer::query(int what, int *outValue) { case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: value = mCore->getMinUndequeuedBufferCountLocked(false); break; + case NATIVE_WINDOW_STICKY_TRANSFORM: + value = static_cast(mStickyTransform); + break; case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: value = (mCore->mQueue.size() > 1); break; diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index 8d9a80032..1e28f9bb8 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -435,6 +435,7 @@ size_t IGraphicBufferProducer::QueueBufferInput::getFlattenedSize() const { + sizeof(crop) + sizeof(scalingMode) + sizeof(transform) + + sizeof(stickyTransform) + sizeof(async) + fence->getFlattenedSize(); } @@ -454,6 +455,7 @@ status_t IGraphicBufferProducer::QueueBufferInput::flatten( FlattenableUtils::write(buffer, size, crop); FlattenableUtils::write(buffer, size, scalingMode); FlattenableUtils::write(buffer, size, transform); + FlattenableUtils::write(buffer, size, stickyTransform); FlattenableUtils::write(buffer, size, async); return fence->flatten(buffer, size, fds, count); } @@ -467,6 +469,7 @@ status_t IGraphicBufferProducer::QueueBufferInput::unflatten( + sizeof(crop) + sizeof(scalingMode) + sizeof(transform) + + sizeof(stickyTransform) + sizeof(async); if (size < minNeeded) { @@ -478,6 +481,7 @@ status_t IGraphicBufferProducer::QueueBufferInput::unflatten( FlattenableUtils::read(buffer, size, crop); FlattenableUtils::read(buffer, size, scalingMode); FlattenableUtils::read(buffer, size, transform); + FlattenableUtils::read(buffer, size, stickyTransform); FlattenableUtils::read(buffer, size, async); fence = new Fence(); diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 8cb9189f1..86451bee7 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -66,6 +66,7 @@ Surface::Surface( mCrop.clear(); mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; mTransform = 0; + mStickyTransform = 0; mDefaultWidth = 0; mDefaultHeight = 0; mUserWidth = 0; @@ -315,15 +316,22 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { sp fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); IGraphicBufferProducer::QueueBufferOutput output; IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp, - crop, mScalingMode, mTransform, mSwapIntervalZero, fence); + crop, mScalingMode, mTransform ^ mStickyTransform, mSwapIntervalZero, + fence, mStickyTransform); 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, + uint32_t hint = 0; + output.deflate(&mDefaultWidth, &mDefaultHeight, &hint, &numPendingBuffers); + // Disable transform hint if sticky transform is set. + if (mStickyTransform == 0) { + mTransformHint = hint; + } + mConsumerRunningBehind = (numPendingBuffers >= 2); return err; @@ -405,6 +413,9 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM: res = dispatchSetBuffersTransform(args); break; + case NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM: + res = dispatchSetBuffersStickyTransform(args); + break; case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP: res = dispatchSetBuffersTimestamp(args); break; @@ -502,6 +513,11 @@ int Surface::dispatchSetBuffersTransform(va_list args) { return setBuffersTransform(transform); } +int Surface::dispatchSetBuffersStickyTransform(va_list args) { + int transform = va_arg(args, int); + return setBuffersStickyTransform(transform); +} + int Surface::dispatchSetBuffersTimestamp(va_list args) { int64_t timestamp = va_arg(args, int64_t); return setBuffersTimestamp(timestamp); @@ -527,8 +543,15 @@ int Surface::connect(int api) { int err = mGraphicBufferProducer->connect(listener, api, mProducerControlledByApp, &output); if (err == NO_ERROR) { uint32_t numPendingBuffers = 0; - output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint, + uint32_t hint = 0; + output.deflate(&mDefaultWidth, &mDefaultHeight, &hint, &numPendingBuffers); + + // Disable transform hint if sticky transform is set. + if (mStickyTransform == 0) { + mTransformHint = hint; + } + mConsumerRunningBehind = (numPendingBuffers >= 2); } if (!err && api == NATIVE_WINDOW_API_CPU) { @@ -552,6 +575,8 @@ int Surface::disconnect(int api) { mCrop.clear(); mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; mTransform = 0; + mStickyTransform = 0; + if (api == NATIVE_WINDOW_API_CPU) { mConnectedToCpu = false; } @@ -678,6 +703,15 @@ int Surface::setBuffersTransform(int transform) return NO_ERROR; } +int Surface::setBuffersStickyTransform(int transform) +{ + ATRACE_CALL(); + ALOGV("Surface::setBuffersStickyTransform"); + Mutex::Autolock lock(mMutex); + mStickyTransform = transform; + return NO_ERROR; +} + int Surface::setBuffersTimestamp(int64_t timestamp) { ALOGV("Surface::setBuffersTimestamp"); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 63bc257f5..4861e3402 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -624,6 +624,17 @@ void Layer::drawWithOpenGL(const sp& hw, engine.disableBlending(); } +uint32_t Layer::getProducerStickyTransform() const { + int producerStickyTransform = 0; + int ret = mProducer->query(NATIVE_WINDOW_STICKY_TRANSFORM, &producerStickyTransform); + if (ret != OK) { + ALOGW("%s: Error %s (%d) while querying window sticky transform.", __FUNCTION__, + strerror(-ret), ret); + return 0; + } + return static_cast(producerStickyTransform); +} + void Layer::setFiltering(bool filtering) { mFiltering = filtering; } @@ -992,10 +1003,12 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions) Layer::State& front; Layer::State& current; bool& recomputeVisibleRegions; + bool stickyTransformSet; Reject(Layer::State& front, Layer::State& current, - bool& recomputeVisibleRegions) + bool& recomputeVisibleRegions, bool stickySet) : front(front), current(current), - recomputeVisibleRegions(recomputeVisibleRegions) { + recomputeVisibleRegions(recomputeVisibleRegions), + stickyTransformSet(stickySet) { } virtual bool reject(const sp& buf, @@ -1058,12 +1071,12 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions) front.requested.crop.getHeight()); } - if (!isFixedSize) { + if (!isFixedSize && !stickyTransformSet) { if (front.active.w != bufWidth || front.active.h != bufHeight) { // reject this buffer - //ALOGD("rejecting buffer: bufWidth=%d, bufHeight=%d, front.active.{w=%d, h=%d}", - // bufWidth, bufHeight, front.active.w, front.active.h); + ALOGE("rejecting buffer: bufWidth=%d, bufHeight=%d, front.active.{w=%d, h=%d}", + bufWidth, bufHeight, front.active.w, front.active.h); return true; } } @@ -1092,8 +1105,8 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions) } }; - - Reject r(mDrawingState, getCurrentState(), recomputeVisibleRegions); + Reject r(mDrawingState, getCurrentState(), recomputeVisibleRegions, + getProducerStickyTransform() != 0); status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r, mFlinger->mPrimaryDispSync); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index ee9f8a088..2d8084df5 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -339,6 +339,9 @@ private: void drawWithOpenGL(const sp& hw, const Region& clip, bool useIdentityTransform) const; + // Temporary - Used only for LEGACY camera mode. + uint32_t getProducerStickyTransform() const; + // -----------------------------------------------------------------------