diff options
Diffstat (limited to 'libs/gui')
79 files changed, 4882 insertions, 1098 deletions
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 9fc16ba930..4a4510e047 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -41,17 +41,26 @@ cc_library_shared { defaults: ["libgui_bufferqueue-defaults"], srcs: [ + ":framework_native_aidl", + ":libgui_bufferqueue_sources", + "BitTube.cpp", + "BLASTBufferQueue.cpp", "BufferHubConsumer.cpp", "BufferHubProducer.cpp", "BufferItemConsumer.cpp", "ConsumerBase.cpp", "CpuConsumer.cpp", "DebugEGLImageTracker.cpp", + "DisplayEventDispatcher.cpp", "DisplayEventReceiver.cpp", "GLConsumer.cpp", "GuiConfig.cpp", + "IConsumerListener.cpp", "IDisplayEventConnection.cpp", + "IGraphicBufferConsumer.cpp", + "IGraphicBufferProducer.cpp", + "IProducerListener.cpp", "IRegionSamplingListener.cpp", "ISurfaceComposer.cpp", "ISurfaceComposerClient.cpp", @@ -59,22 +68,32 @@ cc_library_shared { "LayerDebugInfo.cpp", "LayerMetadata.cpp", "LayerState.cpp", + "OccupancyTracker.cpp", "StreamSplitter.cpp", "Surface.cpp", "SurfaceControl.cpp", "SurfaceComposerClient.cpp", "SyncFeatures.cpp", "view/Surface.cpp", + "bufferqueue/1.0/B2HProducerListener.cpp", + "bufferqueue/1.0/H2BGraphicBufferProducer.cpp", + "bufferqueue/2.0/B2HProducerListener.cpp", + "bufferqueue/2.0/H2BGraphicBufferProducer.cpp", ], shared_libs: [ "android.frameworks.bufferhub@1.0", + "libbinder", "libbufferhub", "libbufferhubqueue", // TODO(b/70046255): Remove this once BufferHub is integrated into libgui. "libinput", "libpdx_default_transport", ], + export_shared_lib_headers: [ + "libbinder", + ], + // bufferhub is not used when building libgui for vendors target: { vendor: { @@ -100,6 +119,10 @@ cc_library_shared { "libdvr_headers", "libpdx_headers", ], + + aidl: { + export_aidl_headers: true, + } } // Used by media codec services exclusively as a static lib for @@ -115,9 +138,37 @@ cc_library_static { cflags: [ "-DNO_BUFFERHUB", + "-DNO_BINDER", ], defaults: ["libgui_bufferqueue-defaults"], + + srcs: [ + ":libgui_bufferqueue_sources", + ], +} + +filegroup { + name: "libgui_bufferqueue_sources", + srcs: [ + "BufferItem.cpp", + "BufferQueue.cpp", + "BufferQueueConsumer.cpp", + "BufferQueueCore.cpp", + "BufferQueueProducer.cpp", + "BufferQueueThreadState.cpp", + "BufferSlot.cpp", + "FrameTimestamps.cpp", + "GLConsumerUtils.cpp", + "HdrMetadata.cpp", + "QueueBufferInputOutput.cpp", + "bufferqueue/1.0/Conversion.cpp", + "bufferqueue/1.0/H2BProducerListener.cpp", + "bufferqueue/1.0/WProducerListener.cpp", + "bufferqueue/2.0/B2HGraphicBufferProducer.cpp", + "bufferqueue/2.0/H2BProducerListener.cpp", + "bufferqueue/2.0/types.cpp", + ], } // Common build config shared by libgui and libgui_bufferqueue_static. @@ -144,34 +195,6 @@ cc_defaults { }, }, - srcs: [ - "BufferItem.cpp", - "BufferQueue.cpp", - "BufferQueueConsumer.cpp", - "BufferQueueCore.cpp", - "BufferQueueProducer.cpp", - "BufferQueueThreadState.cpp", - "BufferSlot.cpp", - "FrameTimestamps.cpp", - "GLConsumerUtils.cpp", - "HdrMetadata.cpp", - "IConsumerListener.cpp", - "IGraphicBufferConsumer.cpp", - "IGraphicBufferProducer.cpp", - "IProducerListener.cpp", - "OccupancyTracker.cpp", - "bufferqueue/1.0/B2HProducerListener.cpp", - "bufferqueue/1.0/Conversion.cpp", - "bufferqueue/1.0/H2BGraphicBufferProducer.cpp", - "bufferqueue/1.0/H2BProducerListener.cpp", - "bufferqueue/1.0/WProducerListener.cpp", - "bufferqueue/2.0/B2HGraphicBufferProducer.cpp", - "bufferqueue/2.0/B2HProducerListener.cpp", - "bufferqueue/2.0/H2BGraphicBufferProducer.cpp", - "bufferqueue/2.0/H2BProducerListener.cpp", - "bufferqueue/2.0/types.cpp", - ], - whole_static_libs: [ "LibGuiProperties", ], @@ -183,7 +206,6 @@ cc_defaults { "android.hardware.graphics.common@1.2", "android.hidl.token@1.0-utils", "libbase", - "libbinder", "libcutils", "libEGL", "libGLESv2", @@ -206,7 +228,6 @@ cc_defaults { ], export_shared_lib_headers: [ - "libbinder", "libEGL", "libnativewindow", "libui", @@ -226,4 +247,21 @@ cc_defaults { ], } +// GMocks for use by external code +cc_library_static { + name: "libgui_mocks", + vendor_available: false, + + defaults: ["libgui_bufferqueue-defaults"], + static_libs: [ + "libgtest", + "libgmock", + ], + + srcs: [ + "mock/GraphicBufferConsumer.cpp", + "mock/GraphicBufferProducer.cpp", + ], +} + subdirs = ["tests"] diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp new file mode 100644 index 0000000000..56591bdc63 --- /dev/null +++ b/libs/gui/BLASTBufferQueue.cpp @@ -0,0 +1,286 @@ +/* + * Copyright (C) 2019 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#undef LOG_TAG +#define LOG_TAG "BLASTBufferQueue" + +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include <gui/BLASTBufferQueue.h> +#include <gui/BufferItemConsumer.h> +#include <gui/GLConsumer.h> + +#include <utils/Trace.h> + +#include <chrono> + +using namespace std::chrono_literals; + +namespace android { + +void BLASTBufferItemConsumer::onDisconnect() { + Mutex::Autolock lock(mFrameEventHistoryMutex); + mPreviouslyConnected = mCurrentlyConnected; + mCurrentlyConnected = false; + if (mPreviouslyConnected) { + mDisconnectEvents.push(mCurrentFrameNumber); + } + mFrameEventHistory.onDisconnect(); +} + +void BLASTBufferItemConsumer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps, + FrameEventHistoryDelta* outDelta) { + Mutex::Autolock lock(mFrameEventHistoryMutex); + if (newTimestamps) { + // BufferQueueProducer only adds a new timestamp on + // queueBuffer + mCurrentFrameNumber = newTimestamps->frameNumber; + mFrameEventHistory.addQueue(*newTimestamps); + } + if (outDelta) { + // frame event histories will be processed + // only after the producer connects and requests + // deltas for the first time. Forward this intent + // to SF-side to turn event processing back on + mPreviouslyConnected = mCurrentlyConnected; + mCurrentlyConnected = true; + mFrameEventHistory.getAndResetDelta(outDelta); + } +} + +void BLASTBufferItemConsumer::updateFrameTimestamps(uint64_t frameNumber, nsecs_t refreshStartTime, + const sp<Fence>& glDoneFence, + const sp<Fence>& presentFence, + const sp<Fence>& prevReleaseFence, + CompositorTiming compositorTiming, + nsecs_t latchTime, nsecs_t dequeueReadyTime) { + Mutex::Autolock lock(mFrameEventHistoryMutex); + + // if the producer is not connected, don't bother updating, + // the next producer that connects won't access this frame event + if (!mCurrentlyConnected) return; + std::shared_ptr<FenceTime> glDoneFenceTime = std::make_shared<FenceTime>(glDoneFence); + std::shared_ptr<FenceTime> presentFenceTime = std::make_shared<FenceTime>(presentFence); + std::shared_ptr<FenceTime> releaseFenceTime = std::make_shared<FenceTime>(prevReleaseFence); + + mFrameEventHistory.addLatch(frameNumber, latchTime); + mFrameEventHistory.addRelease(frameNumber, dequeueReadyTime, std::move(releaseFenceTime)); + mFrameEventHistory.addPreComposition(frameNumber, refreshStartTime); + mFrameEventHistory.addPostComposition(frameNumber, glDoneFenceTime, presentFenceTime, + compositorTiming); +} + +void BLASTBufferItemConsumer::getConnectionEvents(uint64_t frameNumber, bool* needsDisconnect) { + bool disconnect = false; + Mutex::Autolock lock(mFrameEventHistoryMutex); + while (!mDisconnectEvents.empty() && mDisconnectEvents.front() <= frameNumber) { + disconnect = true; + mDisconnectEvents.pop(); + } + if (needsDisconnect != nullptr) *needsDisconnect = disconnect; +} + +BLASTBufferQueue::BLASTBufferQueue(const sp<SurfaceControl>& surface, int width, int height, + bool enableTripleBuffering) + : mSurfaceControl(surface), + mWidth(width), + mHeight(height), + mNextTransaction(nullptr) { + BufferQueue::createBufferQueue(&mProducer, &mConsumer); + // since the adapter is in the client process, set dequeue timeout + // explicitly so that dequeueBuffer will block + mProducer->setDequeueTimeout(std::numeric_limits<int64_t>::max()); + + if (enableTripleBuffering) { + mProducer->setMaxDequeuedBufferCount(2); + } + mBufferItemConsumer = + new BLASTBufferItemConsumer(mConsumer, GraphicBuffer::USAGE_HW_COMPOSER, 1, true); + static int32_t id = 0; + auto name = std::string("BLAST Consumer") + std::to_string(id); + id++; + mBufferItemConsumer->setName(String8(name.c_str())); + mBufferItemConsumer->setFrameAvailableListener(this); + mBufferItemConsumer->setBufferFreedListener(this); + mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight); + mBufferItemConsumer->setDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888); + + mTransformHint = mSurfaceControl->getTransformHint(); + mBufferItemConsumer->setTransformHint(mTransformHint); + + mNumAcquired = 0; + mNumFrameAvailable = 0; + mPendingReleaseItem.item = BufferItem(); + mPendingReleaseItem.releaseFence = nullptr; +} + +void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, int width, int height) { + std::unique_lock _lock{mMutex}; + mSurfaceControl = surface; + + if (mWidth != width || mHeight != height) { + mWidth = width; + mHeight = height; + mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight); + } +} + +static void transactionCallbackThunk(void* context, nsecs_t latchTime, + const sp<Fence>& presentFence, + const std::vector<SurfaceControlStats>& stats) { + if (context == nullptr) { + return; + } + BLASTBufferQueue* bq = static_cast<BLASTBufferQueue*>(context); + bq->transactionCallback(latchTime, presentFence, stats); +} + +void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence>& /*presentFence*/, + const std::vector<SurfaceControlStats>& stats) { + std::unique_lock _lock{mMutex}; + ATRACE_CALL(); + + if (!stats.empty()) { + mTransformHint = stats[0].transformHint; + mBufferItemConsumer->setTransformHint(mTransformHint); + mBufferItemConsumer->updateFrameTimestamps(stats[0].frameEventStats.frameNumber, + stats[0].frameEventStats.refreshStartTime, + stats[0].frameEventStats.gpuCompositionDoneFence, + stats[0].presentFence, + stats[0].previousReleaseFence, + stats[0].frameEventStats.compositorTiming, + stats[0].latchTime, + stats[0].frameEventStats.dequeueReadyTime); + } + if (mPendingReleaseItem.item.mGraphicBuffer != nullptr) { + if (!stats.empty()) { + mPendingReleaseItem.releaseFence = stats[0].previousReleaseFence; + } else { + ALOGE("Warning: no SurfaceControlStats returned in BLASTBufferQueue callback"); + mPendingReleaseItem.releaseFence = nullptr; + } + mBufferItemConsumer->releaseBuffer(mPendingReleaseItem.item, + mPendingReleaseItem.releaseFence + ? mPendingReleaseItem.releaseFence + : Fence::NO_FENCE); + mNumAcquired--; + mPendingReleaseItem.item = BufferItem(); + mPendingReleaseItem.releaseFence = nullptr; + } + + if (mSubmitted.empty()) { + ALOGE("ERROR: callback with no corresponding submitted buffer item"); + } + mPendingReleaseItem.item = std::move(mSubmitted.front()); + mSubmitted.pop(); + + processNextBufferLocked(false); + + mCallbackCV.notify_all(); + decStrong((void*)transactionCallbackThunk); +} + +void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { + ATRACE_CALL(); + if (mNumFrameAvailable == 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS + 1) { + return; + } + + if (mSurfaceControl == nullptr) { + ALOGE("ERROR : surface control is null"); + return; + } + + SurfaceComposerClient::Transaction localTransaction; + bool applyTransaction = true; + SurfaceComposerClient::Transaction* t = &localTransaction; + if (mNextTransaction != nullptr && useNextTransaction) { + t = mNextTransaction; + mNextTransaction = nullptr; + applyTransaction = false; + } + + BufferItem bufferItem; + + status_t status = mBufferItemConsumer->acquireBuffer(&bufferItem, -1, false); + if (status != OK) { + return; + } + auto buffer = bufferItem.mGraphicBuffer; + mNumFrameAvailable--; + + if (buffer == nullptr) { + mBufferItemConsumer->releaseBuffer(bufferItem, Fence::NO_FENCE); + return; + } + + mNumAcquired++; + mSubmitted.push(bufferItem); + + bool needsDisconnect = false; + mBufferItemConsumer->getConnectionEvents(bufferItem.mFrameNumber, &needsDisconnect); + + // if producer disconnected before, notify SurfaceFlinger + if (needsDisconnect) { + t->notifyProducerDisconnect(mSurfaceControl); + } + + // Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback. + incStrong((void*)transactionCallbackThunk); + + t->setBuffer(mSurfaceControl, buffer); + t->setAcquireFence(mSurfaceControl, + bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE); + t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast<void*>(this)); + + t->setFrame(mSurfaceControl, {0, 0, mWidth, mHeight}); + t->setCrop(mSurfaceControl, computeCrop(bufferItem)); + t->setTransform(mSurfaceControl, bufferItem.mTransform); + t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse); + t->setDesiredPresentTime(bufferItem.mTimestamp); + + if (applyTransaction) { + t->apply(); + } +} + +Rect BLASTBufferQueue::computeCrop(const BufferItem& item) { + if (item.mScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) { + return GLConsumer::scaleDownCrop(item.mCrop, mWidth, mHeight); + } + return item.mCrop; +} + +void BLASTBufferQueue::onFrameAvailable(const BufferItem& /*item*/) { + ATRACE_CALL(); + std::unique_lock _lock{mMutex}; + + if (mNextTransaction != nullptr) { + while (mNumFrameAvailable > 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS + 1) { + mCallbackCV.wait(_lock); + } + } + // add to shadow queue + mNumFrameAvailable++; + processNextBufferLocked(true); +} + +void BLASTBufferQueue::setNextTransaction(SurfaceComposerClient::Transaction* t) { + std::lock_guard _lock{mMutex}; + mNextTransaction = t; +} + +} // namespace android diff --git a/libs/gui/BufferHubProducer.cpp b/libs/gui/BufferHubProducer.cpp index 4be014fbb1..1f71e23b4d 100644 --- a/libs/gui/BufferHubProducer.cpp +++ b/libs/gui/BufferHubProducer.cpp @@ -19,7 +19,6 @@ #include <inttypes.h> #include <log/log.h> #include <system/window.h> -#include <ui/BufferHubBuffer.h> namespace android { @@ -697,7 +696,7 @@ String8 BufferHubProducer::getConsumerName() const { // relationship, thus |getConsumerName| from the producer side does not // make any sense. ALOGE("BufferHubProducer::getConsumerName not supported."); - return String8("BufferHubQueue::DummyConsumer"); + return String8("BufferHubQueue::StubConsumer"); } status_t BufferHubProducer::setSharedBufferMode(bool shared_buffer_mode) { diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 5fb3f0b80f..c1d92a2a7f 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -43,6 +43,27 @@ void BufferQueue::ProxyConsumerListener::onDisconnect() { } } +void BufferQueue::ProxyConsumerListener::onFrameDequeued(const uint64_t bufferId) { + sp<ConsumerListener> listener(mConsumerListener.promote()); + if (listener != nullptr) { + listener->onFrameDequeued(bufferId); + } +} + +void BufferQueue::ProxyConsumerListener::onFrameCancelled(const uint64_t bufferId) { + sp<ConsumerListener> listener(mConsumerListener.promote()); + if (listener != nullptr) { + listener->onFrameCancelled(bufferId); + } +} + +void BufferQueue::ProxyConsumerListener::onFrameDetached(const uint64_t bufferId) { + sp<ConsumerListener> listener(mConsumerListener.promote()); + if (listener != nullptr) { + listener->onFrameDetached(bufferId); + } +} + void BufferQueue::ProxyConsumerListener::onFrameAvailable( const BufferItem& item) { sp<ConsumerListener> listener(mConsumerListener.promote()); diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp index 3a7cb44450..da6143c59f 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -44,6 +44,30 @@ namespace android { +// Macros for include BufferQueueCore information in log messages +#define BQ_LOGV(x, ...) \ + ALOGV("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ + ##__VA_ARGS__) +#define BQ_LOGD(x, ...) \ + ALOGD("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ + ##__VA_ARGS__) +#define BQ_LOGI(x, ...) \ + ALOGI("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ + ##__VA_ARGS__) +#define BQ_LOGW(x, ...) \ + ALOGW("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ + ##__VA_ARGS__) +#define BQ_LOGE(x, ...) \ + ALOGE("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ + ##__VA_ARGS__) + +ConsumerListener::~ConsumerListener() = default; + BufferQueueConsumer::BufferQueueConsumer(const sp<BufferQueueCore>& core) : mCore(core), mSlots(core->mSlots), @@ -269,8 +293,9 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, ATRACE_INT(mCore->mConsumerName.string(), static_cast<int32_t>(mCore->mQueue.size())); +#ifndef NO_BINDER mCore->mOccupancyTracker.registerOccupancyChange(mCore->mQueue.size()); - +#endif VALIDATE_CONSISTENCY(); } @@ -743,7 +768,12 @@ status_t BufferQueueConsumer::getSidebandStream(sp<NativeHandle>* outStream) con status_t BufferQueueConsumer::getOccupancyHistory(bool forceFlush, std::vector<OccupancyTracker::Segment>* outHistory) { std::lock_guard<std::mutex> lock(mCore->mMutex); +#ifndef NO_BINDER *outHistory = mCore->mOccupancyTracker.getSegmentHistory(forceFlush); +#else + (void)forceFlush; + outHistory->clear(); +#endif return NO_ERROR; } @@ -764,7 +794,7 @@ status_t BufferQueueConsumer::dumpState(const String8& prefix, String8* outResul bool denied = false; const uid_t uid = BufferQueueThreadState::getCallingUid(); -#ifndef __ANDROID_VNDK__ +#if !defined(__ANDROID_VNDK__) && !defined(NO_BINDER) // permission check can't be done for vendors as vendors have no access to // the PermissionController. We need to do a runtime check as well, since // the system variant of libgui can be loaded in a vendor process. For eg: diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp index 0264bd24a6..5023b6bb81 100644 --- a/libs/gui/BufferQueueCore.cpp +++ b/libs/gui/BufferQueueCore.cpp @@ -28,7 +28,6 @@ #include <inttypes.h> -#include <cutils/properties.h> #include <cutils/atomic.h> #include <gui/BufferItem.h> @@ -42,6 +41,23 @@ namespace android { +// Macros for include BufferQueueCore information in log messages +#define BQ_LOGV(x, ...) \ + ALOGV("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), mUniqueId, \ + mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__) +#define BQ_LOGD(x, ...) \ + ALOGD("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), mUniqueId, \ + mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__) +#define BQ_LOGI(x, ...) \ + ALOGI("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), mUniqueId, \ + mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__) +#define BQ_LOGW(x, ...) \ + ALOGW("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), mUniqueId, \ + mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__) +#define BQ_LOGE(x, ...) \ + ALOGE("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), mUniqueId, \ + mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__) + static String8 getUniqueName() { static volatile int32_t counter = 0; return String8::format("unnamed-%d-%d", getpid(), @@ -54,52 +70,68 @@ static uint64_t getUniqueId() { return id | counter++; } -BufferQueueCore::BufferQueueCore() : - mMutex(), - mIsAbandoned(false), - mConsumerControlledByApp(false), - mConsumerName(getUniqueName()), - mConsumerListener(), - mConsumerUsageBits(0), - mConsumerIsProtected(false), - mConnectedApi(NO_CONNECTED_API), - mLinkedToDeath(), - mConnectedProducerListener(), - mBufferReleasedCbEnabled(false), - mSlots(), - mQueue(), - mFreeSlots(), - mFreeBuffers(), - mUnusedSlots(), - mActiveBuffers(), - mDequeueCondition(), - mDequeueBufferCannotBlock(false), - mQueueBufferCanDrop(false), - mLegacyBufferDrop(true), - mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888), - mDefaultWidth(1), - mDefaultHeight(1), - mDefaultBufferDataSpace(HAL_DATASPACE_UNKNOWN), - mMaxBufferCount(BufferQueueDefs::NUM_BUFFER_SLOTS), - mMaxAcquiredBufferCount(1), - mMaxDequeuedBufferCount(1), - mBufferHasBeenQueued(false), - mFrameCounter(0), - mTransformHint(0), - mIsAllocating(false), - mIsAllocatingCondition(), - mAllowAllocation(true), - mBufferAge(0), - mGenerationNumber(0), - mAsyncMode(false), - mSharedBufferMode(false), - mAutoRefresh(false), - mSharedBufferSlot(INVALID_BUFFER_SLOT), - mSharedBufferCache(Rect::INVALID_RECT, 0, NATIVE_WINDOW_SCALING_MODE_FREEZE, - HAL_DATASPACE_UNKNOWN), - mLastQueuedSlot(INVALID_BUFFER_SLOT), - mUniqueId(getUniqueId()) -{ +static status_t getProcessName(int pid, String8& name) { + FILE* fp = fopen(String8::format("/proc/%d/cmdline", pid), "r"); + if (NULL != fp) { + const size_t size = 64; + char proc_name[size]; + char* result = fgets(proc_name, size, fp); + fclose(fp); + if (result != nullptr) { + name = proc_name; + return NO_ERROR; + } + } + return INVALID_OPERATION; +} + +BufferQueueCore::BufferQueueCore() + : mMutex(), + mIsAbandoned(false), + mConsumerControlledByApp(false), + mConsumerName(getUniqueName()), + mConsumerListener(), + mConsumerUsageBits(0), + mConsumerIsProtected(false), + mConnectedApi(NO_CONNECTED_API), + mLinkedToDeath(), + mConnectedProducerListener(), + mBufferReleasedCbEnabled(false), + mSlots(), + mQueue(), + mFreeSlots(), + mFreeBuffers(), + mUnusedSlots(), + mActiveBuffers(), + mDequeueCondition(), + mDequeueBufferCannotBlock(false), + mQueueBufferCanDrop(false), + mLegacyBufferDrop(true), + mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888), + mDefaultWidth(1), + mDefaultHeight(1), + mDefaultBufferDataSpace(HAL_DATASPACE_UNKNOWN), + mMaxBufferCount(BufferQueueDefs::NUM_BUFFER_SLOTS), + mMaxAcquiredBufferCount(1), + mMaxDequeuedBufferCount(1), + mBufferHasBeenQueued(false), + mFrameCounter(0), + mTransformHint(0), + mIsAllocating(false), + mIsAllocatingCondition(), + mAllowAllocation(true), + mBufferAge(0), + mGenerationNumber(0), + mAsyncMode(false), + mSharedBufferMode(false), + mAutoRefresh(false), + mSharedBufferSlot(INVALID_BUFFER_SLOT), + mSharedBufferCache(Rect::INVALID_RECT, 0, NATIVE_WINDOW_SCALING_MODE_FREEZE, + HAL_DATASPACE_UNKNOWN), + mLastQueuedSlot(INVALID_BUFFER_SLOT), + mUniqueId(getUniqueId()), + mAutoPrerotation(false), + mTransformHintInUse(0) { int numStartingBuffers = getMaxBufferCountLocked(); for (int s = 0; s < numStartingBuffers; s++) { mFreeSlots.insert(s); @@ -124,10 +156,26 @@ void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const mQueueBufferCanDrop, mLegacyBufferDrop); outResult->appendFormat("%s default-size=[%dx%d] default-format=%d ", prefix.string(), mDefaultWidth, mDefaultHeight, mDefaultBufferFormat); - outResult->appendFormat("transform-hint=%02x frame-counter=%" PRIu64, mTransformHint, - mFrameCounter); - - outResult->appendFormat("\n%sFIFO(%zu):\n", prefix.string(), mQueue.size()); + outResult->appendFormat("%s transform-hint=%02x frame-counter=%" PRIu64 "\n", prefix.string(), + mTransformHint, mFrameCounter); + outResult->appendFormat("%s mTransformHintInUse=%02x mAutoPrerotation=%d\n", prefix.string(), + mTransformHintInUse, mAutoPrerotation); + + outResult->appendFormat("%sFIFO(%zu):\n", prefix.string(), mQueue.size()); + + outResult->appendFormat("%s(mConsumerName=%s, ", prefix.string(), mConsumerName.string()); + + outResult->appendFormat("mConnectedApi=%d, mConsumerUsageBits=%" PRIu64 ", ", mConnectedApi, + mConsumerUsageBits); + + String8 producerProcName = String8("\?\?\?"); + String8 consumerProcName = String8("\?\?\?"); + int32_t pid = getpid(); + getProcessName(mConnectedPid, producerProcName); + getProcessName(pid, consumerProcName); + outResult->appendFormat("mId=%" PRIx64 ", producer=[%d:%s], consumer=[%d:%s])\n", mUniqueId, + mConnectedPid, producerProcName.string(), pid, + consumerProcName.string()); Fifo::const_iterator current(mQueue.begin()); while (current != mQueue.end()) { double timestamp = current->mTimestamp / 1e9; diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 4f8eb6b5e8..a7cf39add9 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -44,7 +44,30 @@ namespace android { +// Macros for include BufferQueueCore information in log messages +#define BQ_LOGV(x, ...) \ + ALOGV("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ + ##__VA_ARGS__) +#define BQ_LOGD(x, ...) \ + ALOGD("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ + ##__VA_ARGS__) +#define BQ_LOGI(x, ...) \ + ALOGI("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ + ##__VA_ARGS__) +#define BQ_LOGW(x, ...) \ + ALOGW("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ + ##__VA_ARGS__) +#define BQ_LOGE(x, ...) \ + ALOGE("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ + ##__VA_ARGS__) + static constexpr uint32_t BQ_LAYER_COUNT = 1; +ProducerListener::~ProducerListener() = default; BufferQueueProducer::BufferQueueProducer(const sp<BufferQueueCore>& core, bool consumerIsSurfaceFlinger) : @@ -408,6 +431,10 @@ status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* ou if (useDefaultSize) { width = mCore->mDefaultWidth; height = mCore->mDefaultHeight; + if (mCore->mAutoPrerotation && + (mCore->mTransformHintInUse & NATIVE_WINDOW_TRANSFORM_ROT_90)) { + std::swap(width, height); + } } int found = BufferItem::INVALID_BUFFER_SLOT; @@ -508,6 +535,12 @@ status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* ou mCore->mSharedBufferSlot = found; mSlots[found].mBufferState.mShared = true; } + + if (!(returnFlags & BUFFER_NEEDS_REALLOCATION)) { + if (mCore->mConsumerListener != nullptr) { + mCore->mConsumerListener->onFrameDequeued(mSlots[*outSlot].mGraphicBuffer->getId()); + } + } } // Autolock scope if (returnFlags & BUFFER_NEEDS_REALLOCATION) { @@ -524,6 +557,10 @@ status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* ou if (error == NO_ERROR && !mCore->mIsAbandoned) { graphicBuffer->setGenerationNumber(mCore->mGenerationNumber); mSlots[*outSlot].mGraphicBuffer = graphicBuffer; + if (mCore->mConsumerListener != nullptr) { + mCore->mConsumerListener->onFrameDequeued( + mSlots[*outSlot].mGraphicBuffer->getId()); + } } mCore->mIsAllocating = false; @@ -617,13 +654,17 @@ status_t BufferQueueProducer::detachBuffer(int slot) { return BAD_VALUE; } + listener = mCore->mConsumerListener; + auto gb = mSlots[slot].mGraphicBuffer; + if (listener != nullptr && gb != nullptr) { + listener->onFrameDetached(gb->getId()); + } mSlots[slot].mBufferState.detachProducer(); mCore->mActiveBuffers.erase(slot); mCore->mFreeSlots.insert(slot); mCore->clearBufferSlotLocked(slot); mCore->mDequeueCondition.notify_all(); VALIDATE_CONSISTENCY(); - listener = mCore->mConsumerListener; } if (listener != nullptr) { @@ -960,14 +1001,15 @@ status_t BufferQueueProducer::queueBuffer(int slot, output->width = mCore->mDefaultWidth; output->height = mCore->mDefaultHeight; - output->transformHint = mCore->mTransformHint; + output->transformHint = mCore->mTransformHintInUse = mCore->mTransformHint; output->numPendingBuffers = static_cast<uint32_t>(mCore->mQueue.size()); output->nextFrameNumber = mCore->mFrameCounter + 1; ATRACE_INT(mCore->mConsumerName.string(), static_cast<int32_t>(mCore->mQueue.size())); +#ifndef NO_BINDER mCore->mOccupancyTracker.registerOccupancyChange(mCore->mQueue.size()); - +#endif // Take a ticket for the callback functions callbackTicket = mNextCallbackTicket++; @@ -1079,6 +1121,10 @@ status_t BufferQueueProducer::cancelBuffer(int slot, const sp<Fence>& fence) { mCore->mFreeBuffers.push_back(slot); } + auto gb = mSlots[slot].mGraphicBuffer; + if (mCore->mConsumerListener != nullptr && gb != nullptr) { + mCore->mConsumerListener->onFrameCancelled(gb->getId()); + } mSlots[slot].mFence = fence; mCore->mDequeueCondition.notify_all(); VALIDATE_CONSISTENCY(); @@ -1141,9 +1187,6 @@ int BufferQueueProducer::query(int what, int *outValue) { case NATIVE_WINDOW_CONSUMER_IS_PROTECTED: value = static_cast<int32_t>(mCore->mConsumerIsProtected); break; - case NATIVE_WINDOW_MAX_BUFFER_COUNT: - value = static_cast<int32_t>(mCore->mMaxBufferCount); - break; default: return BAD_VALUE; } @@ -1203,15 +1246,17 @@ status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener, output->width = mCore->mDefaultWidth; output->height = mCore->mDefaultHeight; - output->transformHint = mCore->mTransformHint; + output->transformHint = mCore->mTransformHintInUse = mCore->mTransformHint; output->numPendingBuffers = static_cast<uint32_t>(mCore->mQueue.size()); output->nextFrameNumber = mCore->mFrameCounter + 1; output->bufferReplaced = false; + output->maxBufferCount = mCore->mMaxBufferCount; if (listener != nullptr) { // Set up a death notification so that we can disconnect // automatically if the remote producer dies +#ifndef NO_BINDER if (IInterface::asBinder(listener)->remoteBinder() != nullptr) { status = IInterface::asBinder(listener)->linkToDeath( static_cast<IBinder::DeathRecipient*>(this)); @@ -1221,6 +1266,7 @@ status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener, } mCore->mLinkedToDeath = listener; } +#endif mCore->mConnectedProducerListener = listener; mCore->mBufferReleasedCbEnabled = listener->needsReleaseNotify(); } @@ -1289,6 +1335,7 @@ status_t BufferQueueProducer::disconnect(int api, DisconnectMode mode) { if (mCore->mConnectedApi == api) { mCore->freeAllBuffersLocked(); +#ifndef NO_BINDER // Remove our death notification callback if we have one if (mCore->mLinkedToDeath != nullptr) { sp<IBinder> token = @@ -1298,6 +1345,7 @@ status_t BufferQueueProducer::disconnect(int api, DisconnectMode mode) { token->unlinkToDeath( static_cast<IBinder::DeathRecipient*>(this)); } +#endif mCore->mSharedBufferSlot = BufferQueueCore::INVALID_BUFFER_SLOT; mCore->mLinkedToDeath = nullptr; @@ -1306,6 +1354,7 @@ status_t BufferQueueProducer::disconnect(int api, DisconnectMode mode) { mCore->mConnectedPid = -1; mCore->mSidebandStream.clear(); mCore->mDequeueCondition.notify_all(); + mCore->mAutoPrerotation = false; listener = mCore->mConsumerListener; } else if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) { BQ_LOGE("disconnect: not connected (req=%d)", api); @@ -1349,6 +1398,8 @@ status_t BufferQueueProducer::setSidebandStream(const sp<NativeHandle>& stream) void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, PixelFormat format, uint64_t usage) { ATRACE_CALL(); + + const bool useDefaultSize = !width && !height; while (true) { size_t newBufferCount = 0; uint32_t allocWidth = 0; @@ -1375,6 +1426,11 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, allocWidth = width > 0 ? width : mCore->mDefaultWidth; allocHeight = height > 0 ? height : mCore->mDefaultHeight; + if (useDefaultSize && mCore->mAutoPrerotation && + (mCore->mTransformHintInUse & NATIVE_WINDOW_TRANSFORM_ROT_90)) { + std::swap(allocWidth, allocHeight); + } + allocFormat = format != 0 ? format : mCore->mDefaultBufferFormat; allocUsage = usage | mCore->mConsumerUsageBits; allocName.assign(mCore->mConsumerName.string(), mCore->mConsumerName.size()); @@ -1405,6 +1461,11 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, std::unique_lock<std::mutex> lock(mCore->mMutex); uint32_t checkWidth = width > 0 ? width : mCore->mDefaultWidth; uint32_t checkHeight = height > 0 ? height : mCore->mDefaultHeight; + if (useDefaultSize && mCore->mAutoPrerotation && + (mCore->mTransformHintInUse & NATIVE_WINDOW_TRANSFORM_ROT_90)) { + std::swap(checkWidth, checkHeight); + } + PixelFormat checkFormat = format != 0 ? format : mCore->mDefaultBufferFormat; uint64_t checkUsage = usage | mCore->mConsumerUsageBits; @@ -1607,4 +1668,14 @@ status_t BufferQueueProducer::getConsumerUsage(uint64_t* outUsage) const { return NO_ERROR; } +status_t BufferQueueProducer::setAutoPrerotation(bool autoPrerotation) { + ATRACE_CALL(); + BQ_LOGV("setAutoPrerotation: %d", autoPrerotation); + + std::lock_guard<std::mutex> lock(mCore->mMutex); + + mCore->mAutoPrerotation = autoPrerotation; + return NO_ERROR; +} + } // namespace android diff --git a/libs/gui/BufferQueueThreadState.cpp b/libs/gui/BufferQueueThreadState.cpp index c13030b1ed..976c9b9d50 100644 --- a/libs/gui/BufferQueueThreadState.cpp +++ b/libs/gui/BufferQueueThreadState.cpp @@ -14,8 +14,10 @@ * limitations under the License. */ +#ifndef NO_BINDER #include <binder/IPCThreadState.h> #include <binderthreadstate/CallerUtils.h> +#endif // NO_BINDER #include <hwbinder/IPCThreadState.h> #include <private/gui/BufferQueueThreadState.h> #include <unistd.h> @@ -23,17 +25,25 @@ namespace android { uid_t BufferQueueThreadState::getCallingUid() { +#ifndef NO_BINDER if (getCurrentServingCall() == BinderCallType::HWBINDER) { return hardware::IPCThreadState::self()->getCallingUid(); } return IPCThreadState::self()->getCallingUid(); +#else // NO_BINDER + return hardware::IPCThreadState::self()->getCallingUid(); +#endif // NO_BINDER } pid_t BufferQueueThreadState::getCallingPid() { +#ifndef NO_BINDER if (getCurrentServingCall() == BinderCallType::HWBINDER) { return hardware::IPCThreadState::self()->getCallingPid(); } return IPCThreadState::self()->getCallingPid(); +#else // NO_BINDER + return hardware::IPCThreadState::self()->getCallingPid(); +#endif // NO_BINDER } } // namespace android diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp index abd9921fa9..9f91d9d3aa 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -101,6 +101,48 @@ void ConsumerBase::freeBufferLocked(int slotIndex) { mSlots[slotIndex].mFrameNumber = 0; } +void ConsumerBase::onFrameDequeued(const uint64_t bufferId) { + CB_LOGV("onFrameDequeued"); + + sp<FrameAvailableListener> listener; + { + Mutex::Autolock lock(mFrameAvailableMutex); + listener = mFrameAvailableListener.promote(); + } + + if (listener != nullptr) { + listener->onFrameDequeued(bufferId); + } +} + +void ConsumerBase::onFrameCancelled(const uint64_t bufferId) { + CB_LOGV("onFrameCancelled"); + + sp<FrameAvailableListener> listener; + { + Mutex::Autolock lock(mFrameAvailableMutex); + listener = mFrameAvailableListener.promote(); + } + + if (listener != nullptr) { + listener->onFrameCancelled(bufferId); + } +} + +void ConsumerBase::onFrameDetached(const uint64_t bufferId) { + CB_LOGV("onFrameDetached"); + + sp<FrameAvailableListener> listener; + { + Mutex::Autolock lock(mFrameAvailableMutex); + listener = mFrameAvailableListener.promote(); + } + + if (listener != nullptr) { + listener->onFrameDetached(bufferId); + } +} + void ConsumerBase::onFrameAvailable(const BufferItem& item) { CB_LOGV("onFrameAvailable"); diff --git a/libs/gui/DebugEGLImageTracker.cpp b/libs/gui/DebugEGLImageTracker.cpp index ab6f36444a..5762dabc55 100644 --- a/libs/gui/DebugEGLImageTracker.cpp +++ b/libs/gui/DebugEGLImageTracker.cpp @@ -14,13 +14,14 @@ * limitations under the License. */ +#include <android-base/properties.h> #include <android-base/stringprintf.h> -#include <cutils/properties.h> #include <gui/DebugEGLImageTracker.h> #include <cinttypes> #include <unordered_map> +using android::base::GetBoolProperty; using android::base::StringAppendF; std::mutex DebugEGLImageTracker::mInstanceLock; @@ -57,10 +58,7 @@ private: DebugEGLImageTracker *DebugEGLImageTracker::getInstance() { std::lock_guard lock(mInstanceLock); if (mInstance == nullptr) { - char value[PROPERTY_VALUE_MAX]; - property_get("debug.sf.enable_egl_image_tracker", value, "0"); - const bool enabled = static_cast<bool>(atoi(value)); - + const bool enabled = GetBoolProperty("debug.sf.enable_egl_image_tracker", false); if (enabled) { mInstance = new DebugEGLImageTrackerImpl(); } else { diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp new file mode 100644 index 0000000000..b33bc9e556 --- /dev/null +++ b/libs/gui/DisplayEventDispatcher.cpp @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2015 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "DisplayEventDispatcher" + +#include <cinttypes> +#include <cstdint> + +#include <gui/DisplayEventDispatcher.h> +#include <gui/DisplayEventReceiver.h> +#include <utils/Log.h> +#include <utils/Looper.h> + +#include <utils/Timers.h> + +namespace android { + +// Number of events to read at a time from the DisplayEventDispatcher pipe. +// The value should be large enough that we can quickly drain the pipe +// using just a few large reads. +static const size_t EVENT_BUFFER_SIZE = 100; + +DisplayEventDispatcher::DisplayEventDispatcher(const sp<Looper>& looper, + ISurfaceComposer::VsyncSource vsyncSource, + ISurfaceComposer::ConfigChanged configChanged) + : mLooper(looper), mReceiver(vsyncSource, configChanged), mWaitingForVsync(false) { + ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this); +} + +status_t DisplayEventDispatcher::initialize() { + status_t result = mReceiver.initCheck(); + if (result) { + ALOGW("Failed to initialize display event receiver, status=%d", result); + return result; + } + + if (mLooper != nullptr) { + int rc = mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT, this, NULL); + if (rc < 0) { + return UNKNOWN_ERROR; + } + } + + return OK; +} + +void DisplayEventDispatcher::dispose() { + ALOGV("dispatcher %p ~ Disposing display event dispatcher.", this); + + if (!mReceiver.initCheck() && mLooper != nullptr) { + mLooper->removeFd(mReceiver.getFd()); + } +} + +status_t DisplayEventDispatcher::scheduleVsync() { + if (!mWaitingForVsync) { + ALOGV("dispatcher %p ~ Scheduling vsync.", this); + + // Drain all pending events. + nsecs_t vsyncTimestamp; + PhysicalDisplayId vsyncDisplayId; + uint32_t vsyncCount; + if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) { + ALOGE("dispatcher %p ~ last event processed while scheduling was for %" PRId64 "", this, + ns2ms(static_cast<nsecs_t>(vsyncTimestamp))); + } + + status_t status = mReceiver.requestNextVsync(); + if (status) { + ALOGW("Failed to request next vsync, status=%d", status); + return status; + } + + mWaitingForVsync = true; + } + return OK; +} + +void DisplayEventDispatcher::requestLatestConfig() { + status_t status = mReceiver.requestLatestConfig(); + if (status) { + ALOGW("Failed enable config events, status=%d", status); + return; + } +} + +int DisplayEventDispatcher::getFd() const { + return mReceiver.getFd(); +} + +int DisplayEventDispatcher::handleEvent(int, int events, void*) { + if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) { + ALOGE("Display event receiver pipe was closed or an error occurred. " + "events=0x%x", + events); + return 0; // remove the callback + } + + if (!(events & Looper::EVENT_INPUT)) { + ALOGW("Received spurious callback for unhandled poll event. " + "events=0x%x", + events); + return 1; // keep the callback + } + + // Drain all pending events, keep the last vsync. + nsecs_t vsyncTimestamp; + PhysicalDisplayId vsyncDisplayId; + uint32_t vsyncCount; + if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) { + ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64 + ", displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", count=%d", + this, ns2ms(vsyncTimestamp), vsyncDisplayId, vsyncCount); + mWaitingForVsync = false; + dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount); + } + + return 1; // keep the callback +} + +bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp, + PhysicalDisplayId* outDisplayId, + uint32_t* outCount) { + bool gotVsync = false; + DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE]; + ssize_t n; + while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) { + ALOGV("dispatcher %p ~ Read %d events.", this, int(n)); + for (ssize_t i = 0; i < n; i++) { + const DisplayEventReceiver::Event& ev = buf[i]; + switch (ev.header.type) { + case DisplayEventReceiver::DISPLAY_EVENT_VSYNC: + // Later vsync events will just overwrite the info from earlier + // ones. That's fine, we only care about the most recent. + gotVsync = true; + *outTimestamp = ev.header.timestamp; + *outDisplayId = ev.header.displayId; + *outCount = ev.vsync.count; + break; + case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: + dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected); + break; + case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED: + dispatchConfigChanged(ev.header.timestamp, ev.header.displayId, + ev.config.configId, ev.config.vsyncPeriod); + break; + default: + ALOGW("dispatcher %p ~ ignoring unknown event type %#x", this, ev.header.type); + break; + } + } + } + if (n < 0) { + ALOGW("Failed to get events from display event dispatcher, status=%d", status_t(n)); + } + return gotVsync; +} +} // namespace android diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp index b8faa2df4c..1fed509003 100644 --- a/libs/gui/DisplayEventReceiver.cpp +++ b/libs/gui/DisplayEventReceiver.cpp @@ -79,6 +79,13 @@ status_t DisplayEventReceiver::requestNextVsync() { return NO_INIT; } +status_t DisplayEventReceiver::requestLatestConfig() { + if (mEventConnection != nullptr) { + mEventConnection->requestLatestConfig(); + return NO_ERROR; + } + return NO_INIT; +} ssize_t DisplayEventReceiver::getEvents(DisplayEventReceiver::Event* events, size_t count) { diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp index 3215eca50f..e2ea3f9ab1 100644 --- a/libs/gui/FrameTimestamps.cpp +++ b/libs/gui/FrameTimestamps.cpp @@ -364,6 +364,10 @@ void ConsumerFrameEventHistory::onDisconnect() { mProducerWantsEvents = false; } +void ConsumerFrameEventHistory::setProducerWantsEvents() { + mProducerWantsEvents = true; +} + void ConsumerFrameEventHistory::initializeCompositorTiming( const CompositorTiming& compositorTiming) { mCompositorTiming = compositorTiming; diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp index 8199c98582..30d19e3af4 100644 --- a/libs/gui/GLConsumer.cpp +++ b/libs/gui/GLConsumer.cpp @@ -46,7 +46,6 @@ #include <utils/String8.h> #include <utils/Trace.h> -extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); #define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content" #define EGL_PROTECTED_CONTENT_EXT 0x32C0 @@ -281,7 +280,7 @@ status_t GLConsumer::releaseTexImage() { mCurrentFenceTime = FenceTime::NO_FENCE; if (mAttached) { - // This binds a dummy buffer (mReleasedTexImage). + // This binds a buffer placeholder (mReleasedTexImage). status_t result = bindTextureImageLocked(); if (result != NO_ERROR) { return result; diff --git a/libs/gui/HdrMetadata.cpp b/libs/gui/HdrMetadata.cpp index add3ef0458..058cd9aa3b 100644 --- a/libs/gui/HdrMetadata.cpp +++ b/libs/gui/HdrMetadata.cpp @@ -28,8 +28,8 @@ size_t HdrMetadata::getFlattenedSize() const { size += sizeof(cta8613); } if (validTypes & HDR10PLUS) { - size += sizeof(size_t); - size += hdr10plus.size(); + size += sizeof(uint32_t); + size += hdr10plus.size() * sizeof(hdr10plus[0]); } return size; } @@ -47,10 +47,11 @@ status_t HdrMetadata::flatten(void* buffer, size_t size) const { FlattenableUtils::write(buffer, size, cta8613); } if (validTypes & HDR10PLUS) { - size_t metadataSize = hdr10plus.size(); + uint32_t metadataSize = hdr10plus.size(); FlattenableUtils::write(buffer, size, metadataSize); - memcpy(buffer, hdr10plus.data(), metadataSize); - FlattenableUtils::advance(buffer, size, metadataSize); + size_t metadataSizeinByte = metadataSize * sizeof(hdr10plus[0]); + memcpy(buffer, hdr10plus.data(), metadataSizeinByte); + FlattenableUtils::advance(buffer, size, metadataSizeinByte); } return NO_ERROR; @@ -74,20 +75,21 @@ status_t HdrMetadata::unflatten(void const* buffer, size_t size) { FlattenableUtils::read(buffer, size, cta8613); } if (validTypes & HDR10PLUS) { - if (size < sizeof(size_t)) { + if (size < sizeof(uint32_t)) { return NO_MEMORY; } - size_t metadataSize; + uint32_t metadataSize; FlattenableUtils::read(buffer, size, metadataSize); - if (size < metadataSize) { + size_t metadataSizeinByte = metadataSize * sizeof(hdr10plus[0]); + if (size < metadataSizeinByte) { return NO_MEMORY; } hdr10plus.resize(metadataSize); - memcpy(hdr10plus.data(), buffer, metadataSize); - FlattenableUtils::advance(buffer, size, metadataSize); + memcpy(hdr10plus.data(), buffer, metadataSizeinByte); + FlattenableUtils::advance(buffer, size, metadataSizeinByte); } return NO_ERROR; diff --git a/libs/gui/IConsumerListener.cpp b/libs/gui/IConsumerListener.cpp index 85ac304ab8..f3bd90cffb 100644 --- a/libs/gui/IConsumerListener.cpp +++ b/libs/gui/IConsumerListener.cpp @@ -28,7 +28,10 @@ enum class Tag : uint32_t { ON_FRAME_REPLACED, ON_BUFFERS_RELEASED, ON_SIDEBAND_STREAM_CHANGED, - LAST = ON_SIDEBAND_STREAM_CHANGED, + ON_FRAME_DEQUEUED, + ON_FRAME_CANCELLED, + ON_FRAME_DETACHED, + LAST = ON_FRAME_DETACHED, }; } // Anonymous namespace @@ -44,6 +47,21 @@ public: callRemoteAsync<decltype(&IConsumerListener::onDisconnect)>(Tag::ON_DISCONNECT); } + void onFrameDequeued(const uint64_t bufferId) override { + callRemoteAsync<decltype(&IConsumerListener::onFrameDequeued)>(Tag::ON_FRAME_DEQUEUED, + bufferId); + } + + void onFrameDetached(const uint64_t bufferId) override { + callRemoteAsync<decltype(&IConsumerListener::onFrameDetached)>(Tag::ON_FRAME_DETACHED, + bufferId); + } + + void onFrameCancelled(const uint64_t bufferId) override { + callRemoteAsync<decltype(&IConsumerListener::onFrameCancelled)>(Tag::ON_FRAME_CANCELLED, + bufferId); + } + void onFrameAvailable(const BufferItem& item) override { callRemoteAsync<decltype(&IConsumerListener::onFrameAvailable)>(Tag::ON_FRAME_AVAILABLE, item); @@ -72,7 +90,6 @@ public: // Out-of-line virtual method definitions to trigger vtable emission in this translation unit (see // clang warning -Wweak-vtables) BpConsumerListener::~BpConsumerListener() = default; -ConsumerListener::~ConsumerListener() = default; IMPLEMENT_META_INTERFACE(ConsumerListener, "android.gui.IConsumerListener"); @@ -93,6 +110,12 @@ status_t BnConsumerListener::onTransact(uint32_t code, const Parcel& data, Parce return callLocalAsync(data, reply, &IConsumerListener::onBuffersReleased); case Tag::ON_SIDEBAND_STREAM_CHANGED: return callLocalAsync(data, reply, &IConsumerListener::onSidebandStreamChanged); + case Tag::ON_FRAME_DEQUEUED: + return callLocalAsync(data, reply, &IConsumerListener::onFrameDequeued); + case Tag::ON_FRAME_CANCELLED: + return callLocalAsync(data, reply, &IConsumerListener::onFrameCancelled); + case Tag::ON_FRAME_DETACHED: + return callLocalAsync(data, reply, &IConsumerListener::onFrameDetached); } } diff --git a/libs/gui/IDisplayEventConnection.cpp b/libs/gui/IDisplayEventConnection.cpp index c0e246fa15..aa74bfd3f8 100644 --- a/libs/gui/IDisplayEventConnection.cpp +++ b/libs/gui/IDisplayEventConnection.cpp @@ -26,7 +26,8 @@ enum class Tag : uint32_t { STEAL_RECEIVE_CHANNEL = IBinder::FIRST_CALL_TRANSACTION, SET_VSYNC_RATE, REQUEST_NEXT_VSYNC, - LAST = REQUEST_NEXT_VSYNC, + REQUEST_LATEST_CONFIG, + LAST = REQUEST_LATEST_CONFIG, }; } // Anonymous namespace @@ -53,6 +54,11 @@ public: callRemoteAsync<decltype(&IDisplayEventConnection::requestNextVsync)>( Tag::REQUEST_NEXT_VSYNC); } + + void requestLatestConfig() override { + callRemoteAsync<decltype(&IDisplayEventConnection::requestLatestConfig)>( + Tag::REQUEST_LATEST_CONFIG); + } }; // Out-of-line virtual method definition to trigger vtable emission in this translation unit (see @@ -74,6 +80,8 @@ status_t BnDisplayEventConnection::onTransact(uint32_t code, const Parcel& data, return callLocal(data, reply, &IDisplayEventConnection::setVsyncRate); case Tag::REQUEST_NEXT_VSYNC: return callLocalAsync(data, reply, &IDisplayEventConnection::requestNextVsync); + case Tag::REQUEST_LATEST_CONFIG: + return callLocalAsync(data, reply, &IDisplayEventConnection::requestLatestConfig); } } diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index 0e03b7d393..ad00939976 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -73,6 +73,7 @@ enum { GET_UNIQUE_ID, GET_CONSUMER_USAGE, SET_LEGACY_BUFFER_DROP, + SET_AUTO_PREROTATION, }; class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer> @@ -547,6 +548,17 @@ public: } return actualResult; } + + virtual status_t setAutoPrerotation(bool autoPrerotation) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); + data.writeBool(autoPrerotation); + status_t result = remote()->transact(SET_AUTO_PREROTATION, data, &reply); + if (result == NO_ERROR) { + result = reply.readInt32(); + } + return result; + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -675,6 +687,10 @@ public: status_t getConsumerUsage(uint64_t* outUsage) const override { return mBase->getConsumerUsage(outUsage); } + + status_t setAutoPrerotation(bool autoPrerotation) override { + return mBase->setAutoPrerotation(autoPrerotation); + } }; IMPLEMENT_HYBRID_META_INTERFACE(GraphicBufferProducer, @@ -688,6 +704,12 @@ status_t IGraphicBufferProducer::setLegacyBufferDrop(bool drop) { return INVALID_OPERATION; } +status_t IGraphicBufferProducer::setAutoPrerotation(bool autoPrerotation) { + // No-op for IGBP other than BufferQueue. + (void)autoPrerotation; + return INVALID_OPERATION; +} + status_t IGraphicBufferProducer::exportToParcel(Parcel* parcel) { status_t res = OK; res = parcel->writeUint32(USE_BUFFER_QUEUE); @@ -1050,6 +1072,13 @@ status_t BnGraphicBufferProducer::onTransact( reply->writeInt32(result); return NO_ERROR; } + case SET_AUTO_PREROTATION: { + CHECK_INTERFACE(IGraphicBuffer, data, reply); + bool autoPrerotation = data.readBool(); + status_t result = setAutoPrerotation(autoPrerotation); + reply->writeInt32(result); + return NO_ERROR; + } } return BBinder::onTransact(code, data, reply, flags); } @@ -1060,135 +1089,5 @@ IGraphicBufferProducer::QueueBufferInput::QueueBufferInput(const Parcel& parcel) parcel.read(*this); } -constexpr size_t IGraphicBufferProducer::QueueBufferInput::minFlattenedSize() { - return sizeof(timestamp) + - sizeof(isAutoTimestamp) + - sizeof(dataSpace) + - sizeof(crop) + - sizeof(scalingMode) + - sizeof(transform) + - sizeof(stickyTransform) + - sizeof(getFrameTimestamps); -} - -size_t IGraphicBufferProducer::QueueBufferInput::getFlattenedSize() const { - return minFlattenedSize() + - fence->getFlattenedSize() + - surfaceDamage.getFlattenedSize() + - hdrMetadata.getFlattenedSize(); -} - -size_t IGraphicBufferProducer::QueueBufferInput::getFdCount() const { - return fence->getFdCount(); -} - -status_t IGraphicBufferProducer::QueueBufferInput::flatten( - void*& buffer, size_t& size, int*& fds, size_t& count) const -{ - if (size < getFlattenedSize()) { - return NO_MEMORY; - } - - FlattenableUtils::write(buffer, size, timestamp); - FlattenableUtils::write(buffer, size, isAutoTimestamp); - FlattenableUtils::write(buffer, size, dataSpace); - FlattenableUtils::write(buffer, size, crop); - FlattenableUtils::write(buffer, size, scalingMode); - FlattenableUtils::write(buffer, size, transform); - FlattenableUtils::write(buffer, size, stickyTransform); - FlattenableUtils::write(buffer, size, getFrameTimestamps); - - status_t result = fence->flatten(buffer, size, fds, count); - if (result != NO_ERROR) { - return result; - } - result = surfaceDamage.flatten(buffer, size); - if (result != NO_ERROR) { - return result; - } - FlattenableUtils::advance(buffer, size, surfaceDamage.getFlattenedSize()); - return hdrMetadata.flatten(buffer, size); -} - -status_t IGraphicBufferProducer::QueueBufferInput::unflatten( - void const*& buffer, size_t& size, int const*& fds, size_t& count) -{ - if (size < minFlattenedSize()) { - return NO_MEMORY; - } - - FlattenableUtils::read(buffer, size, timestamp); - FlattenableUtils::read(buffer, size, isAutoTimestamp); - FlattenableUtils::read(buffer, size, dataSpace); - FlattenableUtils::read(buffer, size, crop); - FlattenableUtils::read(buffer, size, scalingMode); - FlattenableUtils::read(buffer, size, transform); - FlattenableUtils::read(buffer, size, stickyTransform); - FlattenableUtils::read(buffer, size, getFrameTimestamps); - - fence = new Fence(); - status_t result = fence->unflatten(buffer, size, fds, count); - if (result != NO_ERROR) { - return result; - } - result = surfaceDamage.unflatten(buffer, size); - if (result != NO_ERROR) { - return result; - } - FlattenableUtils::advance(buffer, size, surfaceDamage.getFlattenedSize()); - return hdrMetadata.unflatten(buffer, size); -} - -// ---------------------------------------------------------------------------- -constexpr size_t IGraphicBufferProducer::QueueBufferOutput::minFlattenedSize() { - return sizeof(width) + - sizeof(height) + - sizeof(transformHint) + - sizeof(numPendingBuffers) + - sizeof(nextFrameNumber) + - sizeof(bufferReplaced); -} - -size_t IGraphicBufferProducer::QueueBufferOutput::getFlattenedSize() const { - return minFlattenedSize() + frameTimestamps.getFlattenedSize(); -} - -size_t IGraphicBufferProducer::QueueBufferOutput::getFdCount() const { - return frameTimestamps.getFdCount(); -} - -status_t IGraphicBufferProducer::QueueBufferOutput::flatten( - void*& buffer, size_t& size, int*& fds, size_t& count) const -{ - if (size < getFlattenedSize()) { - return NO_MEMORY; - } - - FlattenableUtils::write(buffer, size, width); - FlattenableUtils::write(buffer, size, height); - FlattenableUtils::write(buffer, size, transformHint); - FlattenableUtils::write(buffer, size, numPendingBuffers); - FlattenableUtils::write(buffer, size, nextFrameNumber); - FlattenableUtils::write(buffer, size, bufferReplaced); - - return frameTimestamps.flatten(buffer, size, fds, count); -} - -status_t IGraphicBufferProducer::QueueBufferOutput::unflatten( - void const*& buffer, size_t& size, int const*& fds, size_t& count) -{ - if (size < minFlattenedSize()) { - return NO_MEMORY; - } - - FlattenableUtils::read(buffer, size, width); - FlattenableUtils::read(buffer, size, height); - FlattenableUtils::read(buffer, size, transformHint); - FlattenableUtils::read(buffer, size, numPendingBuffers); - FlattenableUtils::read(buffer, size, nextFrameNumber); - FlattenableUtils::read(buffer, size, bufferReplaced); - - return frameTimestamps.unflatten(buffer, size, fds, count); -} }; // namespace android diff --git a/libs/gui/IProducerListener.cpp b/libs/gui/IProducerListener.cpp index 808e3369f1..0683087211 100644 --- a/libs/gui/IProducerListener.cpp +++ b/libs/gui/IProducerListener.cpp @@ -119,9 +119,7 @@ status_t BnProducerListener::onTransact(uint32_t code, const Parcel& data, return BBinder::onTransact(code, data, reply, flags); } -ProducerListener::~ProducerListener() = default; - -DummyProducerListener::~DummyProducerListener() = default; +StubProducerListener::~StubProducerListener() = default; bool BnProducerListener::needsReleaseNotify() { return true; diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 12deaf0bd6..e62a61fc55 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -34,8 +34,10 @@ #include <system/graphics.h> +#include <ui/DisplayConfig.h> #include <ui/DisplayInfo.h> #include <ui/DisplayStatInfo.h> +#include <ui/DisplayState.h> #include <ui/HdrCapabilities.h> #include <utils/Log.h> @@ -69,7 +71,7 @@ public: const sp<IBinder>& applyToken, const InputWindowCommands& commands, int64_t desiredPresentTime, - const client_cache_t& uncacheBuffer, + const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); @@ -90,10 +92,11 @@ public: data.writeInt64(desiredPresentTime); data.writeStrongBinder(uncacheBuffer.token.promote()); data.writeUint64(uncacheBuffer.id); + data.writeBool(hasListenerCallbacks); if (data.writeVectorSize(listenerCallbacks) == NO_ERROR) { for (const auto& [listener, callbackIds] : listenerCallbacks) { - data.writeStrongBinder(IInterface::asBinder(listener)); + data.writeStrongBinder(listener); data.writeInt64Vector(callbackIds); } } @@ -109,10 +112,10 @@ public: } virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer, - bool& outCapturedSecureLayers, const ui::Dataspace reqDataspace, - const ui::PixelFormat reqPixelFormat, Rect sourceCrop, + bool& outCapturedSecureLayers, ui::Dataspace reqDataspace, + ui::PixelFormat reqPixelFormat, const Rect& sourceCrop, uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform, - ISurfaceComposer::Rotation rotation, bool captureSecureLayers) { + ui::Rotation rotation, bool captureSecureLayers) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); @@ -350,22 +353,43 @@ public: remote()->transact(BnSurfaceComposer::SET_POWER_MODE, data, &reply); } - virtual status_t getDisplayConfigs(const sp<IBinder>& display, - Vector<DisplayInfo>* configs) - { + virtual status_t getDisplayState(const sp<IBinder>& display, ui::DisplayState* state) { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + data.writeStrongBinder(display); + remote()->transact(BnSurfaceComposer::GET_DISPLAY_STATE, data, &reply); + const status_t result = reply.readInt32(); + if (result == NO_ERROR) { + memcpy(state, reply.readInplace(sizeof(ui::DisplayState)), sizeof(ui::DisplayState)); + } + return result; + } + + virtual status_t getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info) { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + data.writeStrongBinder(display); + remote()->transact(BnSurfaceComposer::GET_DISPLAY_INFO, data, &reply); + const status_t result = reply.readInt32(); + if (result == NO_ERROR) { + memcpy(info, reply.readInplace(sizeof(DisplayInfo)), sizeof(DisplayInfo)); + } + return result; + } + + virtual status_t getDisplayConfigs(const sp<IBinder>& display, Vector<DisplayConfig>* configs) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); remote()->transact(BnSurfaceComposer::GET_DISPLAY_CONFIGS, data, &reply); - status_t result = reply.readInt32(); + const status_t result = reply.readInt32(); if (result == NO_ERROR) { - size_t numConfigs = reply.readUint32(); + const size_t numConfigs = reply.readUint32(); configs->clear(); configs->resize(numConfigs); for (size_t c = 0; c < numConfigs; ++c) { - memcpy(&(configs->editItemAt(c)), - reply.readInplace(sizeof(DisplayInfo)), - sizeof(DisplayInfo)); + memcpy(&(configs->editItemAt(c)), reply.readInplace(sizeof(DisplayConfig)), + sizeof(DisplayConfig)); } } return result; @@ -396,32 +420,6 @@ public: return reply.readInt32(); } - virtual status_t setActiveConfig(const sp<IBinder>& display, int id) - { - Parcel data, reply; - status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (result != NO_ERROR) { - ALOGE("setActiveConfig failed to writeInterfaceToken: %d", result); - return result; - } - result = data.writeStrongBinder(display); - if (result != NO_ERROR) { - ALOGE("setActiveConfig failed to writeStrongBinder: %d", result); - return result; - } - result = data.writeInt32(id); - if (result != NO_ERROR) { - ALOGE("setActiveConfig failed to writeInt32: %d", result); - return result; - } - result = remote()->transact(BnSurfaceComposer::SET_ACTIVE_CONFIG, data, &reply); - if (result != NO_ERROR) { - ALOGE("setActiveConfig failed to transact: %d", result); - return result; - } - return reply.readInt32(); - } - virtual status_t getDisplayColorModes(const sp<IBinder>& display, Vector<ColorMode>* outColorModes) { Parcel data, reply; @@ -524,6 +522,88 @@ public: return static_cast<status_t>(reply.readInt32()); } + virtual status_t getAutoLowLatencyModeSupport(const sp<IBinder>& display, + bool* outSupport) const { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + status_t result = data.writeStrongBinder(display); + if (result != NO_ERROR) { + ALOGE("getAutoLowLatencyModeSupport failed to writeStrongBinder: %d", result); + return result; + } + result = remote()->transact(BnSurfaceComposer::GET_AUTO_LOW_LATENCY_MODE_SUPPORT, data, + &reply); + if (result != NO_ERROR) { + ALOGE("getAutoLowLatencyModeSupport failed to transact: %d", result); + return result; + } + return reply.readBool(outSupport); + } + + virtual void setAutoLowLatencyMode(const sp<IBinder>& display, bool on) { + Parcel data, reply; + status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + if (result != NO_ERROR) { + ALOGE("setAutoLowLatencyMode failed to writeInterfaceToken: %d", result); + return; + } + + result = data.writeStrongBinder(display); + if (result != NO_ERROR) { + ALOGE("setAutoLowLatencyMode failed to writeStrongBinder: %d", result); + return; + } + result = data.writeBool(on); + if (result != NO_ERROR) { + ALOGE("setAutoLowLatencyMode failed to writeBool: %d", result); + return; + } + result = remote()->transact(BnSurfaceComposer::SET_AUTO_LOW_LATENCY_MODE, data, &reply); + if (result != NO_ERROR) { + ALOGE("setAutoLowLatencyMode failed to transact: %d", result); + return; + } + } + + virtual status_t getGameContentTypeSupport(const sp<IBinder>& display, bool* outSupport) const { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + status_t result = data.writeStrongBinder(display); + if (result != NO_ERROR) { + ALOGE("getGameContentTypeSupport failed to writeStrongBinder: %d", result); + return result; + } + result = remote()->transact(BnSurfaceComposer::GET_GAME_CONTENT_TYPE_SUPPORT, data, &reply); + if (result != NO_ERROR) { + ALOGE("getGameContentTypeSupport failed to transact: %d", result); + return result; + } + return reply.readBool(outSupport); + } + + virtual void setGameContentType(const sp<IBinder>& display, bool on) { + Parcel data, reply; + status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + if (result != NO_ERROR) { + ALOGE("setGameContentType failed to writeInterfaceToken: %d", result); + return; + } + result = data.writeStrongBinder(display); + if (result != NO_ERROR) { + ALOGE("setGameContentType failed to writeStrongBinder: %d", result); + return; + } + result = data.writeBool(on); + if (result != NO_ERROR) { + ALOGE("setGameContentType failed to writeBool: %d", result); + return; + } + result = remote()->transact(BnSurfaceComposer::SET_GAME_CONTENT_TYPE, data, &reply); + if (result != NO_ERROR) { + ALOGE("setGameContentType failed to transact: %d", result); + } + } + virtual status_t clearAnimationFrameStats() { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); @@ -611,8 +691,7 @@ public: return result; } - virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const - { + virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) { if (!outLayers) { return UNEXPECTED_NULL; } @@ -715,8 +794,7 @@ public: } virtual status_t setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable, - uint8_t componentMask, - uint64_t maxFrames) const { + uint8_t componentMask, uint64_t maxFrames) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); @@ -851,54 +929,112 @@ public: return error; } - virtual status_t setAllowedDisplayConfigs(const sp<IBinder>& displayToken, - const std::vector<int32_t>& allowedConfigs) { + virtual status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken, + int32_t defaultConfig, + float primaryRefreshRateMin, + float primaryRefreshRateMax, + float appRequestRefreshRateMin, + float appRequestRefreshRateMax) { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { - ALOGE("setAllowedDisplayConfigs failed to writeInterfaceToken: %d", result); + ALOGE("setDesiredDisplayConfigSpecs: failed to writeInterfaceToken: %d", result); return result; } result = data.writeStrongBinder(displayToken); if (result != NO_ERROR) { - ALOGE("setAllowedDisplayConfigs failed to writeStrongBinder: %d", result); + ALOGE("setDesiredDisplayConfigSpecs: failed to write display token: %d", result); + return result; + } + result = data.writeInt32(defaultConfig); + if (result != NO_ERROR) { + ALOGE("setDesiredDisplayConfigSpecs failed to write defaultConfig: %d", result); + return result; + } + result = data.writeFloat(primaryRefreshRateMin); + if (result != NO_ERROR) { + ALOGE("setDesiredDisplayConfigSpecs failed to write primaryRefreshRateMin: %d", result); + return result; + } + result = data.writeFloat(primaryRefreshRateMax); + if (result != NO_ERROR) { + ALOGE("setDesiredDisplayConfigSpecs failed to write primaryRefreshRateMax: %d", result); return result; } - result = data.writeInt32Vector(allowedConfigs); + result = data.writeFloat(appRequestRefreshRateMin); if (result != NO_ERROR) { - ALOGE("setAllowedDisplayConfigs failed to writeInt32Vector: %d", result); + ALOGE("setDesiredDisplayConfigSpecs failed to write appRequestRefreshRateMin: %d", + result); return result; } - result = remote()->transact(BnSurfaceComposer::SET_ALLOWED_DISPLAY_CONFIGS, data, &reply); + result = data.writeFloat(appRequestRefreshRateMax); if (result != NO_ERROR) { - ALOGE("setAllowedDisplayConfigs failed to transact: %d", result); + ALOGE("setDesiredDisplayConfigSpecs failed to write appRequestRefreshRateMax: %d", + result); + return result; + } + + result = remote()->transact(BnSurfaceComposer::SET_DESIRED_DISPLAY_CONFIG_SPECS, data, + &reply); + if (result != NO_ERROR) { + ALOGE("setDesiredDisplayConfigSpecs failed to transact: %d", result); return result; } return reply.readInt32(); } - virtual status_t getAllowedDisplayConfigs(const sp<IBinder>& displayToken, - std::vector<int32_t>* outAllowedConfigs) { - if (!outAllowedConfigs) return BAD_VALUE; + virtual status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken, + int32_t* outDefaultConfig, + float* outPrimaryRefreshRateMin, + float* outPrimaryRefreshRateMax, + float* outAppRequestRefreshRateMin, + float* outAppRequestRefreshRateMax) { + if (!outDefaultConfig || !outPrimaryRefreshRateMin || !outPrimaryRefreshRateMax || + !outAppRequestRefreshRateMin || !outAppRequestRefreshRateMax) { + return BAD_VALUE; + } Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { - ALOGE("getAllowedDisplayConfigs failed to writeInterfaceToken: %d", result); + ALOGE("getDesiredDisplayConfigSpecs failed to writeInterfaceToken: %d", result); return result; } result = data.writeStrongBinder(displayToken); if (result != NO_ERROR) { - ALOGE("getAllowedDisplayConfigs failed to writeStrongBinder: %d", result); + ALOGE("getDesiredDisplayConfigSpecs failed to writeStrongBinder: %d", result); return result; } - result = remote()->transact(BnSurfaceComposer::GET_ALLOWED_DISPLAY_CONFIGS, data, &reply); + result = remote()->transact(BnSurfaceComposer::GET_DESIRED_DISPLAY_CONFIG_SPECS, data, + &reply); if (result != NO_ERROR) { - ALOGE("getAllowedDisplayConfigs failed to transact: %d", result); + ALOGE("getDesiredDisplayConfigSpecs failed to transact: %d", result); return result; } - result = reply.readInt32Vector(outAllowedConfigs); + result = reply.readInt32(outDefaultConfig); if (result != NO_ERROR) { - ALOGE("getAllowedDisplayConfigs failed to readInt32Vector: %d", result); + ALOGE("getDesiredDisplayConfigSpecs failed to read defaultConfig: %d", result); + return result; + } + result = reply.readFloat(outPrimaryRefreshRateMin); + if (result != NO_ERROR) { + ALOGE("getDesiredDisplayConfigSpecs failed to read primaryRefreshRateMin: %d", result); + return result; + } + result = reply.readFloat(outPrimaryRefreshRateMax); + if (result != NO_ERROR) { + ALOGE("getDesiredDisplayConfigSpecs failed to read primaryRefreshRateMax: %d", result); + return result; + } + result = reply.readFloat(outAppRequestRefreshRateMin); + if (result != NO_ERROR) { + ALOGE("getDesiredDisplayConfigSpecs failed to read appRequestRefreshRateMin: %d", + result); + return result; + } + result = reply.readFloat(outAppRequestRefreshRateMax); + if (result != NO_ERROR) { + ALOGE("getDesiredDisplayConfigSpecs failed to read appRequestRefreshRateMax: %d", + result); return result; } return reply.readInt32(); @@ -932,7 +1068,7 @@ public: return NO_ERROR; } - virtual status_t setDisplayBrightness(const sp<IBinder>& displayToken, float brightness) const { + virtual status_t setDisplayBrightness(const sp<IBinder>& displayToken, float brightness) { Parcel data, reply; status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (error != NO_ERROR) { @@ -977,6 +1113,106 @@ public: } return NO_ERROR; } + + virtual status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, + float lightPosY, float lightPosZ, float lightRadius) { + Parcel data, reply; + status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + if (error != NO_ERROR) { + ALOGE("setGlobalShadowSettings: failed to write interface token: %d", error); + return error; + } + + std::vector<float> shadowConfig = {ambientColor.r, ambientColor.g, ambientColor.b, + ambientColor.a, spotColor.r, spotColor.g, + spotColor.b, spotColor.a, lightPosY, + lightPosZ, lightRadius}; + + error = data.writeFloatVector(shadowConfig); + if (error != NO_ERROR) { + ALOGE("setGlobalShadowSettings: failed to write shadowConfig: %d", error); + return error; + } + + error = remote()->transact(BnSurfaceComposer::SET_GLOBAL_SHADOW_SETTINGS, data, &reply, + IBinder::FLAG_ONEWAY); + if (error != NO_ERROR) { + ALOGE("setGlobalShadowSettings: failed to transact: %d", error); + return error; + } + return NO_ERROR; + } + + virtual status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate, + int8_t compatibility) { + Parcel data, reply; + status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + if (err != NO_ERROR) { + ALOGE("setFrameRate: failed writing interface token: %s (%d)", strerror(-err), -err); + return err; + } + + err = data.writeStrongBinder(IInterface::asBinder(surface)); + if (err != NO_ERROR) { + ALOGE("setFrameRate: failed writing strong binder: %s (%d)", strerror(-err), -err); + return err; + } + + err = data.writeFloat(frameRate); + if (err != NO_ERROR) { + ALOGE("setFrameRate: failed writing float: %s (%d)", strerror(-err), -err); + return err; + } + + err = data.writeByte(compatibility); + if (err != NO_ERROR) { + ALOGE("setFrameRate: failed writing byte: %s (%d)", strerror(-err), -err); + return err; + } + + err = remote()->transact(BnSurfaceComposer::SET_FRAME_RATE, data, &reply); + if (err != NO_ERROR) { + ALOGE("setFrameRate: failed to transact: %s (%d)", strerror(-err), err); + return err; + } + + return reply.readInt32(); + } + + virtual status_t acquireFrameRateFlexibilityToken(sp<IBinder>* outToken) { + if (!outToken) return BAD_VALUE; + + Parcel data, reply; + status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + if (err != NO_ERROR) { + ALOGE("acquireFrameRateFlexibilityToken: failed writing interface token: %s (%d)", + strerror(-err), -err); + return err; + } + + err = remote()->transact(BnSurfaceComposer::ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN, data, + &reply); + if (err != NO_ERROR) { + ALOGE("acquireFrameRateFlexibilityToken: failed to transact: %s (%d)", strerror(-err), + err); + return err; + } + + err = reply.readInt32(); + if (err != NO_ERROR) { + ALOGE("acquireFrameRateFlexibilityToken: call failed: %s (%d)", strerror(-err), err); + return err; + } + + err = reply.readStrongBinder(outToken); + if (err != NO_ERROR) { + ALOGE("acquireFrameRateFlexibilityToken: failed reading binder token: %s (%d)", + strerror(-err), err); + return err; + } + + return NO_ERROR; + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -1039,18 +1275,19 @@ status_t BnSurfaceComposer::onTransact( uncachedBuffer.token = data.readStrongBinder(); uncachedBuffer.id = data.readUint64(); + bool hasListenerCallbacks = data.readBool(); + std::vector<ListenerCallbacks> listenerCallbacks; int32_t listenersSize = data.readInt32(); for (int32_t i = 0; i < listenersSize; i++) { - auto listener = - interface_cast<ITransactionCompletedListener>(data.readStrongBinder()); + auto listener = data.readStrongBinder(); std::vector<CallbackId> callbackIds; data.readInt64Vector(&callbackIds); listenerCallbacks.emplace_back(listener, callbackIds); } - setTransactionState(state, displays, stateFlags, applyToken, inputWindowCommands, - desiredPresentTime, uncachedBuffer, listenerCallbacks); + desiredPresentTime, uncachedBuffer, hasListenerCallbacks, + listenerCallbacks); return NO_ERROR; } case BOOT_FINISHED: { @@ -1075,8 +1312,7 @@ status_t BnSurfaceComposer::onTransact( bool capturedSecureLayers = false; status_t res = captureScreen(display, &outBuffer, capturedSecureLayers, reqDataspace, reqPixelFormat, sourceCrop, reqWidth, reqHeight, - useIdentityTransform, - static_cast<ISurfaceComposer::Rotation>(rotation), + useIdentityTransform, ui::toRotation(rotation), captureSecureLayers); reply->writeInt32(res); @@ -1110,6 +1346,9 @@ status_t BnSurfaceComposer::onTransact( std::unordered_set<sp<IBinder>, SpHash<IBinder>> excludeHandles; int numExcludeHandles = data.readInt32(); + if (numExcludeHandles >= static_cast<int>(MAX_LAYERS)) { + return BAD_VALUE; + } excludeHandles.reserve(numExcludeHandles); for (int i = 0; i < numExcludeHandles; i++) { excludeHandles.emplace(data.readStrongBinder()); @@ -1185,17 +1424,40 @@ status_t BnSurfaceComposer::onTransact( reply->writeStrongBinder(display); return NO_ERROR; } + case GET_DISPLAY_STATE: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + ui::DisplayState state; + const sp<IBinder> display = data.readStrongBinder(); + const status_t result = getDisplayState(display, &state); + reply->writeInt32(result); + if (result == NO_ERROR) { + memcpy(reply->writeInplace(sizeof(ui::DisplayState)), &state, + sizeof(ui::DisplayState)); + } + return NO_ERROR; + } + case GET_DISPLAY_INFO: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + DisplayInfo info; + const sp<IBinder> display = data.readStrongBinder(); + const status_t result = getDisplayInfo(display, &info); + reply->writeInt32(result); + if (result == NO_ERROR) { + memcpy(reply->writeInplace(sizeof(DisplayInfo)), &info, sizeof(DisplayInfo)); + } + return NO_ERROR; + } case GET_DISPLAY_CONFIGS: { CHECK_INTERFACE(ISurfaceComposer, data, reply); - Vector<DisplayInfo> configs; - sp<IBinder> display = data.readStrongBinder(); - status_t result = getDisplayConfigs(display, &configs); + Vector<DisplayConfig> configs; + const sp<IBinder> display = data.readStrongBinder(); + const status_t result = getDisplayConfigs(display, &configs); reply->writeInt32(result); if (result == NO_ERROR) { reply->writeUint32(static_cast<uint32_t>(configs.size())); for (size_t c = 0; c < configs.size(); ++c) { - memcpy(reply->writeInplace(sizeof(DisplayInfo)), - &configs[c], sizeof(DisplayInfo)); + memcpy(reply->writeInplace(sizeof(DisplayConfig)), &configs[c], + sizeof(DisplayConfig)); } } return NO_ERROR; @@ -1219,14 +1481,6 @@ status_t BnSurfaceComposer::onTransact( reply->writeInt32(id); return NO_ERROR; } - case SET_ACTIVE_CONFIG: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IBinder> display = data.readStrongBinder(); - int id = data.readInt32(); - status_t result = setActiveConfig(display, id); - reply->writeInt32(result); - return NO_ERROR; - } case GET_DISPLAY_COLOR_MODES: { CHECK_INTERFACE(ISurfaceComposer, data, reply); Vector<ColorMode> colorModes; @@ -1297,6 +1551,75 @@ status_t BnSurfaceComposer::onTransact( result = reply->writeInt32(result); return result; } + + case GET_AUTO_LOW_LATENCY_MODE_SUPPORT: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp<IBinder> display = nullptr; + status_t result = data.readStrongBinder(&display); + if (result != NO_ERROR) { + ALOGE("getAutoLowLatencyModeSupport failed to readStrongBinder: %d", result); + return result; + } + bool supported = false; + result = getAutoLowLatencyModeSupport(display, &supported); + if (result == NO_ERROR) { + result = reply->writeBool(supported); + } + return result; + } + + case SET_AUTO_LOW_LATENCY_MODE: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp<IBinder> display = nullptr; + status_t result = data.readStrongBinder(&display); + if (result != NO_ERROR) { + ALOGE("setAutoLowLatencyMode failed to readStrongBinder: %d", result); + return result; + } + bool setAllm = false; + result = data.readBool(&setAllm); + if (result != NO_ERROR) { + ALOGE("setAutoLowLatencyMode failed to readBool: %d", result); + return result; + } + setAutoLowLatencyMode(display, setAllm); + return result; + } + + case GET_GAME_CONTENT_TYPE_SUPPORT: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp<IBinder> display = nullptr; + status_t result = data.readStrongBinder(&display); + if (result != NO_ERROR) { + ALOGE("getGameContentTypeSupport failed to readStrongBinder: %d", result); + return result; + } + bool supported = false; + result = getGameContentTypeSupport(display, &supported); + if (result == NO_ERROR) { + result = reply->writeBool(supported); + } + return result; + } + + case SET_GAME_CONTENT_TYPE: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp<IBinder> display = nullptr; + status_t result = data.readStrongBinder(&display); + if (result != NO_ERROR) { + ALOGE("setGameContentType failed to readStrongBinder: %d", result); + return result; + } + bool setGameContentTypeOn = false; + result = data.readBool(&setGameContentTypeOn); + if (result != NO_ERROR) { + ALOGE("setGameContentType failed to readBool: %d", result); + return result; + } + setGameContentType(display, setGameContentTypeOn); + return result; + } + case CLEAR_ANIMATION_FRAME_STATS: { CHECK_INTERFACE(ISurfaceComposer, data, reply); status_t result = clearAnimationFrameStats(); @@ -1534,21 +1857,106 @@ status_t BnSurfaceComposer::onTransact( } return removeRegionSamplingListener(listener); } - case SET_ALLOWED_DISPLAY_CONFIGS: { + case SET_DESIRED_DISPLAY_CONFIG_SPECS: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp<IBinder> displayToken = data.readStrongBinder(); - std::vector<int32_t> allowedConfigs; - data.readInt32Vector(&allowedConfigs); - status_t result = setAllowedDisplayConfigs(displayToken, allowedConfigs); + int32_t defaultConfig; + status_t result = data.readInt32(&defaultConfig); + if (result != NO_ERROR) { + ALOGE("setDesiredDisplayConfigSpecs: failed to read defaultConfig: %d", result); + return result; + } + float primaryRefreshRateMin; + result = data.readFloat(&primaryRefreshRateMin); + if (result != NO_ERROR) { + ALOGE("setDesiredDisplayConfigSpecs: failed to read primaryRefreshRateMin: %d", + result); + return result; + } + float primaryRefreshRateMax; + result = data.readFloat(&primaryRefreshRateMax); + if (result != NO_ERROR) { + ALOGE("setDesiredDisplayConfigSpecs: failed to read primaryRefreshRateMax: %d", + result); + return result; + } + float appRequestRefreshRateMin; + result = data.readFloat(&appRequestRefreshRateMin); + if (result != NO_ERROR) { + ALOGE("setDesiredDisplayConfigSpecs: failed to read appRequestRefreshRateMin: %d", + result); + return result; + } + float appRequestRefreshRateMax; + result = data.readFloat(&appRequestRefreshRateMax); + if (result != NO_ERROR) { + ALOGE("setDesiredDisplayConfigSpecs: failed to read appRequestRefreshRateMax: %d", + result); + return result; + } + result = + setDesiredDisplayConfigSpecs(displayToken, defaultConfig, primaryRefreshRateMin, + primaryRefreshRateMax, appRequestRefreshRateMin, + appRequestRefreshRateMax); + if (result != NO_ERROR) { + ALOGE("setDesiredDisplayConfigSpecs: failed to call setDesiredDisplayConfigSpecs: " + "%d", + result); + return result; + } reply->writeInt32(result); return result; } - case GET_ALLOWED_DISPLAY_CONFIGS: { + case GET_DESIRED_DISPLAY_CONFIG_SPECS: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp<IBinder> displayToken = data.readStrongBinder(); - std::vector<int32_t> allowedConfigs; - status_t result = getAllowedDisplayConfigs(displayToken, &allowedConfigs); - reply->writeInt32Vector(allowedConfigs); + int32_t defaultConfig; + float primaryRefreshRateMin; + float primaryRefreshRateMax; + float appRequestRefreshRateMin; + float appRequestRefreshRateMax; + + status_t result = + getDesiredDisplayConfigSpecs(displayToken, &defaultConfig, + &primaryRefreshRateMin, &primaryRefreshRateMax, + &appRequestRefreshRateMin, + &appRequestRefreshRateMax); + if (result != NO_ERROR) { + ALOGE("getDesiredDisplayConfigSpecs: failed to get getDesiredDisplayConfigSpecs: " + "%d", + result); + return result; + } + + result = reply->writeInt32(defaultConfig); + if (result != NO_ERROR) { + ALOGE("getDesiredDisplayConfigSpecs: failed to write defaultConfig: %d", result); + return result; + } + result = reply->writeFloat(primaryRefreshRateMin); + if (result != NO_ERROR) { + ALOGE("getDesiredDisplayConfigSpecs: failed to write primaryRefreshRateMin: %d", + result); + return result; + } + result = reply->writeFloat(primaryRefreshRateMax); + if (result != NO_ERROR) { + ALOGE("getDesiredDisplayConfigSpecs: failed to write primaryRefreshRateMax: %d", + result); + return result; + } + result = reply->writeFloat(appRequestRefreshRateMin); + if (result != NO_ERROR) { + ALOGE("getDesiredDisplayConfigSpecs: failed to write appRequestRefreshRateMin: %d", + result); + return result; + } + result = reply->writeFloat(appRequestRefreshRateMax); + if (result != NO_ERROR) { + ALOGE("getDesiredDisplayConfigSpecs: failed to write appRequestRefreshRateMax: %d", + result); + return result; + } reply->writeInt32(result); return result; } @@ -1591,6 +1999,65 @@ status_t BnSurfaceComposer::onTransact( } return notifyPowerHint(hintId); } + case SET_GLOBAL_SHADOW_SETTINGS: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + + std::vector<float> shadowConfig; + status_t error = data.readFloatVector(&shadowConfig); + if (error != NO_ERROR || shadowConfig.size() != 11) { + ALOGE("setGlobalShadowSettings: failed to read shadowConfig: %d", error); + return error; + } + + half4 ambientColor = {shadowConfig[0], shadowConfig[1], shadowConfig[2], + shadowConfig[3]}; + half4 spotColor = {shadowConfig[4], shadowConfig[5], shadowConfig[6], shadowConfig[7]}; + float lightPosY = shadowConfig[8]; + float lightPosZ = shadowConfig[9]; + float lightRadius = shadowConfig[10]; + return setGlobalShadowSettings(ambientColor, spotColor, lightPosY, lightPosZ, + lightRadius); + } + case SET_FRAME_RATE: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp<IBinder> binder; + status_t err = data.readStrongBinder(&binder); + if (err != NO_ERROR) { + ALOGE("setFrameRate: failed to read strong binder: %s (%d)", strerror(-err), -err); + return err; + } + sp<IGraphicBufferProducer> surface = interface_cast<IGraphicBufferProducer>(binder); + if (!surface) { + ALOGE("setFrameRate: failed to cast to IGraphicBufferProducer: %s (%d)", + strerror(-err), -err); + return err; + } + float frameRate; + err = data.readFloat(&frameRate); + if (err != NO_ERROR) { + ALOGE("setFrameRate: failed to read float: %s (%d)", strerror(-err), -err); + return err; + } + int8_t compatibility; + err = data.readByte(&compatibility); + if (err != NO_ERROR) { + ALOGE("setFrameRate: failed to read byte: %s (%d)", strerror(-err), -err); + return err; + } + status_t result = setFrameRate(surface, frameRate, compatibility); + reply->writeInt32(result); + return NO_ERROR; + } + case ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp<IBinder> token; + status_t result = acquireFrameRateFlexibilityToken(&token); + reply->writeInt32(result); + if (result == NO_ERROR) { + reply->writeStrongBinder(token); + } + return NO_ERROR; + } default: { return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp index 129558bd15..621cf5950b 100644 --- a/libs/gui/ISurfaceComposerClient.cpp +++ b/libs/gui/ISurfaceComposerClient.cpp @@ -34,7 +34,8 @@ enum class Tag : uint32_t { CREATE_WITH_SURFACE_PARENT, CLEAR_LAYER_FRAME_STATS, GET_LAYER_FRAME_STATS, - LAST = GET_LAYER_FRAME_STATS, + MIRROR_SURFACE, + LAST = MIRROR_SURFACE, }; } // Anonymous namespace @@ -48,25 +49,28 @@ public: status_t createSurface(const String8& name, uint32_t width, uint32_t height, PixelFormat format, uint32_t flags, const sp<IBinder>& parent, LayerMetadata metadata, - sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp) override { + sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, + uint32_t* outTransformHint) override { return callRemote<decltype(&ISurfaceComposerClient::createSurface)>(Tag::CREATE_SURFACE, name, width, height, format, flags, parent, std::move(metadata), - handle, gbp); + handle, gbp, + outTransformHint); } status_t createWithSurfaceParent(const String8& name, uint32_t width, uint32_t height, PixelFormat format, uint32_t flags, const sp<IGraphicBufferProducer>& parent, LayerMetadata metadata, sp<IBinder>* handle, - sp<IGraphicBufferProducer>* gbp) override { + sp<IGraphicBufferProducer>* gbp, + uint32_t* outTransformHint) override { return callRemote<decltype( &ISurfaceComposerClient::createWithSurfaceParent)>(Tag::CREATE_WITH_SURFACE_PARENT, name, width, height, format, flags, parent, - std::move(metadata), handle, - gbp); + std::move(metadata), handle, gbp, + outTransformHint); } status_t clearLayerFrameStats(const sp<IBinder>& handle) const override { @@ -80,6 +84,12 @@ public: &ISurfaceComposerClient::getLayerFrameStats)>(Tag::GET_LAYER_FRAME_STATS, handle, outStats); } + + status_t mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle) override { + return callRemote<decltype(&ISurfaceComposerClient::mirrorSurface)>(Tag::MIRROR_SURFACE, + mirrorFromHandle, + outHandle); + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -105,6 +115,8 @@ status_t BnSurfaceComposerClient::onTransact(uint32_t code, const Parcel& data, return callLocal(data, reply, &ISurfaceComposerClient::clearLayerFrameStats); case Tag::GET_LAYER_FRAME_STATS: return callLocal(data, reply, &ISurfaceComposerClient::getLayerFrameStats); + case Tag::MIRROR_SURFACE: + return callLocal(data, reply, &ISurfaceComposerClient::mirrorSurface); } } diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp index 74cd4f1ede..69f7894d07 100644 --- a/libs/gui/ITransactionCompletedListener.cpp +++ b/libs/gui/ITransactionCompletedListener.cpp @@ -30,6 +30,66 @@ enum class Tag : uint32_t { } // Anonymous namespace +status_t FrameEventHistoryStats::writeToParcel(Parcel* output) const { + status_t err = output->writeUint64(frameNumber); + if (err != NO_ERROR) return err; + + if (gpuCompositionDoneFence) { + err = output->writeBool(true); + if (err != NO_ERROR) return err; + + err = output->write(*gpuCompositionDoneFence); + } else { + err = output->writeBool(false); + } + if (err != NO_ERROR) return err; + + err = output->writeInt64(compositorTiming.deadline); + if (err != NO_ERROR) return err; + + err = output->writeInt64(compositorTiming.interval); + if (err != NO_ERROR) return err; + + err = output->writeInt64(compositorTiming.presentLatency); + if (err != NO_ERROR) return err; + + err = output->writeInt64(refreshStartTime); + if (err != NO_ERROR) return err; + + err = output->writeInt64(dequeueReadyTime); + return err; +} + +status_t FrameEventHistoryStats::readFromParcel(const Parcel* input) { + status_t err = input->readUint64(&frameNumber); + if (err != NO_ERROR) return err; + + bool hasFence = false; + err = input->readBool(&hasFence); + if (err != NO_ERROR) return err; + + if (hasFence) { + gpuCompositionDoneFence = new Fence(); + err = input->read(*gpuCompositionDoneFence); + if (err != NO_ERROR) return err; + } + + err = input->readInt64(&(compositorTiming.deadline)); + if (err != NO_ERROR) return err; + + err = input->readInt64(&(compositorTiming.interval)); + if (err != NO_ERROR) return err; + + err = input->readInt64(&(compositorTiming.presentLatency)); + if (err != NO_ERROR) return err; + + err = input->readInt64(&refreshStartTime); + if (err != NO_ERROR) return err; + + err = input->readInt64(&dequeueReadyTime); + return err; +} + status_t SurfaceStats::writeToParcel(Parcel* output) const { status_t err = output->writeStrongBinder(surfaceControl); if (err != NO_ERROR) { @@ -48,6 +108,12 @@ status_t SurfaceStats::writeToParcel(Parcel* output) const { } else { err = output->writeBool(false); } + err = output->writeUint32(transformHint); + if (err != NO_ERROR) { + return err; + } + + err = output->writeParcelable(eventStats); return err; } @@ -72,7 +138,13 @@ status_t SurfaceStats::readFromParcel(const Parcel* input) { return err; } } - return NO_ERROR; + err = input->readUint32(&transformHint); + if (err != NO_ERROR) { + return err; + } + + err = input->readParcelable(&eventStats); + return err; } status_t TransactionStats::writeToParcel(Parcel* output) const { @@ -151,7 +223,7 @@ status_t ListenerStats::readFromParcel(const Parcel* input) { return NO_ERROR; } -ListenerStats ListenerStats::createEmpty(const sp<ITransactionCompletedListener>& listener, +ListenerStats ListenerStats::createEmpty(const sp<IBinder>& listener, const std::unordered_set<CallbackId>& callbackIds) { ListenerStats listenerStats; listenerStats.listener = listener; diff --git a/libs/gui/LayerMetadata.cpp b/libs/gui/LayerMetadata.cpp index 04d2871c77..b3eb9940b2 100644 --- a/libs/gui/LayerMetadata.cpp +++ b/libs/gui/LayerMetadata.cpp @@ -18,6 +18,8 @@ #include <binder/Parcel.h> #include <gui/LayerMetadata.h> +#include "android/view/LayerMetadataKey.h" + using android::base::StringPrintf; namespace android { @@ -113,12 +115,12 @@ void LayerMetadata::setInt32(uint32_t key, int32_t value) { std::string LayerMetadata::itemToString(uint32_t key, const char* separator) const { if (!has(key)) return std::string(); - switch (key) { - case METADATA_OWNER_UID: + switch (static_cast<view::LayerMetadataKey>(key)) { + case view::LayerMetadataKey::METADATA_OWNER_UID: return StringPrintf("ownerUID%s%d", separator, getInt32(key, 0)); - case METADATA_WINDOW_TYPE: + case view::LayerMetadataKey::METADATA_WINDOW_TYPE: return StringPrintf("windowType%s%d", separator, getInt32(key, 0)); - case METADATA_TASK_ID: + case view::LayerMetadataKey::METADATA_TASK_ID: return StringPrintf("taskId%s%d", separator, getInt32(key, 0)); default: return StringPrintf("%d%s%dbytes", key, separator, diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 42eb9213d6..0281279d69 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -24,6 +24,8 @@ #include <gui/IGraphicBufferProducer.h> #include <gui/LayerState.h> +#include <cmath> + namespace android { status_t layer_state_t::write(Parcel& output) const @@ -86,7 +88,7 @@ status_t layer_state_t::write(Parcel& output) const memcpy(output.writeInplace(16 * sizeof(float)), colorTransform.asArray(), 16 * sizeof(float)); output.writeFloat(cornerRadius); - output.writeBool(hasListenerCallbacks); + output.writeUint32(backgroundBlurRadius); output.writeStrongBinder(cachedBuffer.token.promote()); output.writeUint64(cachedBuffer.id); output.writeParcelable(metadata); @@ -95,6 +97,26 @@ status_t layer_state_t::write(Parcel& output) const output.writeUint32(static_cast<uint32_t>(bgColorDataspace)); output.writeBool(colorSpaceAgnostic); + auto err = output.writeVectorSize(listeners); + if (err) { + return err; + } + + for (auto listener : listeners) { + err = output.writeStrongBinder(listener.transactionCompletedListener); + if (err) { + return err; + } + err = output.writeInt64Vector(listener.callbackIds); + if (err) { + return err; + } + } + output.writeFloat(shadowRadius); + output.writeInt32(frameRateSelectionPriority); + output.writeFloat(frameRate); + output.writeByte(frameRateCompatibility); + output.writeUint32(fixedTransformHint); return NO_ERROR; } @@ -154,9 +176,14 @@ status_t layer_state_t::read(const Parcel& input) sidebandStream = NativeHandle::create(input.readNativeHandle(), true); } - colorTransform = mat4(static_cast<const float*>(input.readInplace(16 * sizeof(float)))); + const void* color_transform_data = input.readInplace(16 * sizeof(float)); + if (color_transform_data) { + colorTransform = mat4(static_cast<const float*>(color_transform_data)); + } else { + return BAD_VALUE; + } cornerRadius = input.readFloat(); - hasListenerCallbacks = input.readBool(); + backgroundBlurRadius = input.readUint32(); cachedBuffer.token = input.readStrongBinder(); cachedBuffer.id = input.readUint64(); input.readParcelable(&metadata); @@ -165,16 +192,27 @@ status_t layer_state_t::read(const Parcel& input) bgColorDataspace = static_cast<ui::Dataspace>(input.readUint32()); colorSpaceAgnostic = input.readBool(); + int32_t numListeners = input.readInt32(); + listeners.clear(); + for (int i = 0; i < numListeners; i++) { + auto listener = input.readStrongBinder(); + std::vector<CallbackId> callbackIds; + input.readInt64Vector(&callbackIds); + listeners.emplace_back(listener, callbackIds); + } + shadowRadius = input.readFloat(); + frameRateSelectionPriority = input.readInt32(); + frameRate = input.readFloat(); + frameRateCompatibility = input.readByte(); + fixedTransformHint = static_cast<ui::Transform::RotationFlags>(input.readUint32()); return NO_ERROR; } status_t ComposerState::write(Parcel& output) const { - output.writeStrongBinder(IInterface::asBinder(client)); return state.write(output); } status_t ComposerState::read(const Parcel& input) { - client = interface_cast<ISurfaceComposerClient>(input.readStrongBinder()); return state.read(input); } @@ -182,7 +220,6 @@ status_t ComposerState::read(const Parcel& input) { DisplayState::DisplayState() : what(0), layerStack(0), - orientation(eOrientationDefault), viewport(Rect::EMPTY_RECT), frame(Rect::EMPTY_RECT), width(0), @@ -194,7 +231,7 @@ status_t DisplayState::write(Parcel& output) const { output.writeStrongBinder(IInterface::asBinder(surface)); output.writeUint32(what); output.writeUint32(layerStack); - output.writeUint32(orientation); + output.writeUint32(toRotationInt(orientation)); output.write(viewport); output.write(frame); output.writeUint32(width); @@ -207,7 +244,7 @@ status_t DisplayState::read(const Parcel& input) { surface = interface_cast<IGraphicBufferProducer>(input.readStrongBinder()); what = input.readUint32(); layerStack = input.readUint32(); - orientation = input.readUint32(); + orientation = ui::toRotation(input.readUint32()); input.read(viewport); input.read(frame); width = input.readUint32(); @@ -267,8 +304,9 @@ void layer_state_t::merge(const layer_state_t& other) { } if (other.what & eFlagsChanged) { what |= eFlagsChanged; - flags = other.flags; - mask = other.mask; + flags &= ~other.mask; + flags |= (other.flags & other.mask); + mask |= other.mask; } if (other.what & eLayerStackChanged) { what |= eLayerStackChanged; @@ -282,6 +320,10 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eCornerRadiusChanged; cornerRadius = other.cornerRadius; } + if (other.what & eBackgroundBlurRadiusChanged) { + what |= eBackgroundBlurRadiusChanged; + backgroundBlurRadius = other.backgroundBlurRadius; + } if (other.what & eDeferTransaction_legacy) { what |= eDeferTransaction_legacy; barrierHandle_legacy = other.barrierHandle_legacy; @@ -292,9 +334,6 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eOverrideScalingModeChanged; overrideScalingMode = other.overrideScalingMode; } - if (other.what & eGeometryAppliesWithResize) { - what |= eGeometryAppliesWithResize; - } if (other.what & eReparentChildren) { what |= eReparentChildren; reparentHandle = other.reparentHandle; @@ -365,7 +404,6 @@ void layer_state_t::merge(const layer_state_t& other) { } if (other.what & eHasListenerCallbacksChanged) { what |= eHasListenerCallbacksChanged; - hasListenerCallbacks = other.hasListenerCallbacks; } #ifndef NO_INPUT @@ -389,6 +427,23 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eMetadataChanged; metadata.merge(other.metadata); } + if (other.what & eShadowRadiusChanged) { + what |= eShadowRadiusChanged; + shadowRadius = other.shadowRadius; + } + if (other.what & eFrameRateSelectionPriority) { + what |= eFrameRateSelectionPriority; + frameRateSelectionPriority = other.frameRateSelectionPriority; + } + if (other.what & eFrameRateChanged) { + what |= eFrameRateChanged; + frameRate = other.frameRate; + frameRateCompatibility = other.frameRateCompatibility; + } + if (other.what & eFixedTransformHintChanged) { + what |= eFixedTransformHintChanged; + fixedTransformHint = other.fixedTransformHint; + } if ((other.what & what) != other.what) { ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? " "other.what=0x%" PRIu64 " what=0x%" PRIu64, @@ -399,40 +454,36 @@ void layer_state_t::merge(const layer_state_t& other) { // ------------------------------- InputWindowCommands ---------------------------------------- void InputWindowCommands::merge(const InputWindowCommands& other) { - transferTouchFocusCommands - .insert(transferTouchFocusCommands.end(), - std::make_move_iterator(other.transferTouchFocusCommands.begin()), - std::make_move_iterator(other.transferTouchFocusCommands.end())); - syncInputWindows |= other.syncInputWindows; } void InputWindowCommands::clear() { - transferTouchFocusCommands.clear(); syncInputWindows = false; } void InputWindowCommands::write(Parcel& output) const { - output.writeUint32(static_cast<uint32_t>(transferTouchFocusCommands.size())); - for (const auto& transferTouchFocusCommand : transferTouchFocusCommands) { - output.writeStrongBinder(transferTouchFocusCommand.fromToken); - output.writeStrongBinder(transferTouchFocusCommand.toToken); - } - output.writeBool(syncInputWindows); } void InputWindowCommands::read(const Parcel& input) { - size_t count = input.readUint32(); - transferTouchFocusCommands.clear(); - for (size_t i = 0; i < count; i++) { - TransferTouchFocusCommand transferTouchFocusCommand; - transferTouchFocusCommand.fromToken = input.readStrongBinder(); - transferTouchFocusCommand.toToken = input.readStrongBinder(); - transferTouchFocusCommands.emplace_back(transferTouchFocusCommand); + syncInputWindows = input.readBool(); +} + +bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* inFunctionName) { + const char* functionName = inFunctionName != nullptr ? inFunctionName : "call"; + int floatClassification = std::fpclassify(frameRate); + if (frameRate < 0 || floatClassification == FP_INFINITE || floatClassification == FP_NAN) { + ALOGE("%s failed - invalid frame rate %f", functionName, frameRate); + return false; } - syncInputWindows = input.readBool(); + if (compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT && + compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE) { + ALOGE("%s failed - invalid compatibility value %d", functionName, compatibility); + return false; + } + + return true; } }; // namespace android diff --git a/libs/gui/QueueBufferInputOutput.cpp b/libs/gui/QueueBufferInputOutput.cpp new file mode 100644 index 0000000000..30f0ef6785 --- /dev/null +++ b/libs/gui/QueueBufferInputOutput.cpp @@ -0,0 +1,159 @@ +/* + * Copyright 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <inttypes.h> + +#define LOG_TAG "QueueBufferInputOutput" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS +//#define LOG_NDEBUG 0 + +#include <gui/IGraphicBufferProducer.h> + +namespace android { + +constexpr size_t IGraphicBufferProducer::QueueBufferInput::minFlattenedSize() { + return sizeof(timestamp) + + sizeof(isAutoTimestamp) + + sizeof(dataSpace) + + sizeof(crop) + + sizeof(scalingMode) + + sizeof(transform) + + sizeof(stickyTransform) + + sizeof(getFrameTimestamps); +} + +IGraphicBufferProducer::QueueBufferInput::QueueBufferInput(const Parcel& parcel) { + parcel.read(*this); +} + +size_t IGraphicBufferProducer::QueueBufferInput::getFlattenedSize() const { + return minFlattenedSize() + + fence->getFlattenedSize() + + surfaceDamage.getFlattenedSize() + + hdrMetadata.getFlattenedSize(); +} + +size_t IGraphicBufferProducer::QueueBufferInput::getFdCount() const { + return fence->getFdCount(); +} + +status_t IGraphicBufferProducer::QueueBufferInput::flatten( + void*& buffer, size_t& size, int*& fds, size_t& count) const +{ + if (size < getFlattenedSize()) { + return NO_MEMORY; + } + + FlattenableUtils::write(buffer, size, timestamp); + FlattenableUtils::write(buffer, size, isAutoTimestamp); + FlattenableUtils::write(buffer, size, dataSpace); + FlattenableUtils::write(buffer, size, crop); + FlattenableUtils::write(buffer, size, scalingMode); + FlattenableUtils::write(buffer, size, transform); + FlattenableUtils::write(buffer, size, stickyTransform); + FlattenableUtils::write(buffer, size, getFrameTimestamps); + + status_t result = fence->flatten(buffer, size, fds, count); + if (result != NO_ERROR) { + return result; + } + result = surfaceDamage.flatten(buffer, size); + if (result != NO_ERROR) { + return result; + } + FlattenableUtils::advance(buffer, size, surfaceDamage.getFlattenedSize()); + return hdrMetadata.flatten(buffer, size); +} + +status_t IGraphicBufferProducer::QueueBufferInput::unflatten( + void const*& buffer, size_t& size, int const*& fds, size_t& count) +{ + if (size < minFlattenedSize()) { + return NO_MEMORY; + } + + FlattenableUtils::read(buffer, size, timestamp); + FlattenableUtils::read(buffer, size, isAutoTimestamp); + FlattenableUtils::read(buffer, size, dataSpace); + FlattenableUtils::read(buffer, size, crop); + FlattenableUtils::read(buffer, size, scalingMode); + FlattenableUtils::read(buffer, size, transform); + FlattenableUtils::read(buffer, size, stickyTransform); + FlattenableUtils::read(buffer, size, getFrameTimestamps); + + fence = new Fence(); + status_t result = fence->unflatten(buffer, size, fds, count); + if (result != NO_ERROR) { + return result; + } + result = surfaceDamage.unflatten(buffer, size); + if (result != NO_ERROR) { + return result; + } + FlattenableUtils::advance(buffer, size, surfaceDamage.getFlattenedSize()); + return hdrMetadata.unflatten(buffer, size); +} + +//////////////////////////////////////////////////////////////////////// +constexpr size_t IGraphicBufferProducer::QueueBufferOutput::minFlattenedSize() { + return sizeof(width) + sizeof(height) + sizeof(transformHint) + sizeof(numPendingBuffers) + + sizeof(nextFrameNumber) + sizeof(bufferReplaced) + sizeof(maxBufferCount); +} +size_t IGraphicBufferProducer::QueueBufferOutput::getFlattenedSize() const { + return minFlattenedSize() + frameTimestamps.getFlattenedSize(); +} + +size_t IGraphicBufferProducer::QueueBufferOutput::getFdCount() const { + return frameTimestamps.getFdCount(); +} + +status_t IGraphicBufferProducer::QueueBufferOutput::flatten( + void*& buffer, size_t& size, int*& fds, size_t& count) const +{ + if (size < getFlattenedSize()) { + return NO_MEMORY; + } + + FlattenableUtils::write(buffer, size, width); + FlattenableUtils::write(buffer, size, height); + FlattenableUtils::write(buffer, size, transformHint); + FlattenableUtils::write(buffer, size, numPendingBuffers); + FlattenableUtils::write(buffer, size, nextFrameNumber); + FlattenableUtils::write(buffer, size, bufferReplaced); + FlattenableUtils::write(buffer, size, maxBufferCount); + + return frameTimestamps.flatten(buffer, size, fds, count); +} + +status_t IGraphicBufferProducer::QueueBufferOutput::unflatten( + void const*& buffer, size_t& size, int const*& fds, size_t& count) +{ + if (size < minFlattenedSize()) { + return NO_MEMORY; + } + + FlattenableUtils::read(buffer, size, width); + FlattenableUtils::read(buffer, size, height); + FlattenableUtils::read(buffer, size, transformHint); + FlattenableUtils::read(buffer, size, numPendingBuffers); + FlattenableUtils::read(buffer, size, nextFrameNumber); + FlattenableUtils::read(buffer, size, bufferReplaced); + FlattenableUtils::read(buffer, size, maxBufferCount); + + return frameTimestamps.unflatten(buffer, size, fds, count); +} + +} // namespace android diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index b822319d22..c3323fefb2 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -43,6 +43,7 @@ #include <gui/IProducerListener.h> #include <gui/ISurfaceComposer.h> +#include <gui/LayerState.h> #include <private/gui/ComposerService.h> namespace android { @@ -50,6 +51,18 @@ namespace android { using ui::ColorMode; using ui::Dataspace; +namespace { + +bool isInterceptorRegistrationOp(int op) { + return op == NATIVE_WINDOW_SET_CANCEL_INTERCEPTOR || + op == NATIVE_WINDOW_SET_DEQUEUE_INTERCEPTOR || + op == NATIVE_WINDOW_SET_PERFORM_INTERCEPTOR || + op == NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR || + op == NATIVE_WINDOW_SET_QUERY_INTERCEPTOR; +} + +} // namespace + Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp) : mGraphicBufferProducer(bufferProducer), mCrop(Rect::EMPTY_RECT), @@ -97,6 +110,7 @@ Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controll mConnectedToCpu = false; mProducerControlledByApp = controlledByApp; mSwapIntervalZero = false; + mMaxBufferCount = NUM_BUFFER_SLOTS; } Surface::~Surface() { @@ -365,18 +379,58 @@ int Surface::hook_setSwapInterval(ANativeWindow* window, int interval) { int Surface::hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer, int* fenceFd) { Surface* c = getSelf(window); + { + std::shared_lock<std::shared_mutex> lock(c->mInterceptorMutex); + if (c->mDequeueInterceptor != nullptr) { + auto interceptor = c->mDequeueInterceptor; + auto data = c->mDequeueInterceptorData; + return interceptor(window, Surface::dequeueBufferInternal, data, buffer, fenceFd); + } + } + return c->dequeueBuffer(buffer, fenceFd); +} + +int Surface::dequeueBufferInternal(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); + { + std::shared_lock<std::shared_mutex> lock(c->mInterceptorMutex); + if (c->mCancelInterceptor != nullptr) { + auto interceptor = c->mCancelInterceptor; + auto data = c->mCancelInterceptorData; + return interceptor(window, Surface::cancelBufferInternal, data, buffer, fenceFd); + } + } + return c->cancelBuffer(buffer, fenceFd); +} + +int Surface::cancelBufferInternal(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); + { + std::shared_lock<std::shared_mutex> lock(c->mInterceptorMutex); + if (c->mQueueInterceptor != nullptr) { + auto interceptor = c->mQueueInterceptor; + auto data = c->mQueueInterceptorData; + return interceptor(window, Surface::queueBufferInternal, data, buffer, fenceFd); + } + } + return c->queueBuffer(buffer, fenceFd); +} + +int Surface::queueBufferInternal(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd) { + Surface* c = getSelf(window); return c->queueBuffer(buffer, fenceFd); } @@ -419,21 +473,51 @@ int Surface::hook_queueBuffer_DEPRECATED(ANativeWindow* window, return c->queueBuffer(buffer, -1); } -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); - int result = c->perform(operation, args); + int result; + // Don't acquire shared ownership of the interceptor mutex if we're going to + // do interceptor registration, as otherwise we'll deadlock on acquiring + // exclusive ownership. + if (!isInterceptorRegistrationOp(operation)) { + std::shared_lock<std::shared_mutex> lock(c->mInterceptorMutex); + if (c->mPerformInterceptor != nullptr) { + result = c->mPerformInterceptor(window, Surface::performInternal, + c->mPerformInterceptorData, operation, args); + va_end(args); + return result; + } + } + result = c->perform(operation, args); va_end(args); return result; } +int Surface::performInternal(ANativeWindow* window, int operation, va_list args) { + Surface* c = getSelf(window); + return c->perform(operation, args); +} + +int Surface::hook_query(const ANativeWindow* window, int what, int* value) { + const Surface* c = getSelf(window); + { + std::shared_lock<std::shared_mutex> lock(c->mInterceptorMutex); + if (c->mQueryInterceptor != nullptr) { + auto interceptor = c->mQueryInterceptor; + auto data = c->mQueryInterceptorData; + return interceptor(window, Surface::queryInternal, data, what, value); + } + } + return c->query(what, value); +} + +int Surface::queryInternal(const ANativeWindow* window, int what, int* value) { + const Surface* c = getSelf(window); + return c->query(what, value); +} + int Surface::setSwapInterval(int interval) { ATRACE_CALL(); // EGL specification states: @@ -962,6 +1046,10 @@ int Surface::query(int what, int* value) const { *value = static_cast<int>(mDataSpace); return NO_ERROR; } + case NATIVE_WINDOW_MAX_BUFFER_COUNT: { + *value = mMaxBufferCount; + return NO_ERROR; + } } } return mGraphicBufferProducer->query(what, value); @@ -1073,6 +1161,46 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_GET_CONSUMER_USAGE64: res = dispatchGetConsumerUsage64(args); break; + case NATIVE_WINDOW_SET_AUTO_PREROTATION: + res = dispatchSetAutoPrerotation(args); + break; + case NATIVE_WINDOW_GET_LAST_DEQUEUE_START: + res = dispatchGetLastDequeueStartTime(args); + break; + case NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT: + res = dispatchSetDequeueTimeout(args); + break; + case NATIVE_WINDOW_GET_LAST_DEQUEUE_DURATION: + res = dispatchGetLastDequeueDuration(args); + break; + case NATIVE_WINDOW_GET_LAST_QUEUE_DURATION: + res = dispatchGetLastQueueDuration(args); + break; + case NATIVE_WINDOW_SET_FRAME_RATE: + res = dispatchSetFrameRate(args); + break; + case NATIVE_WINDOW_SET_CANCEL_INTERCEPTOR: + res = dispatchAddCancelInterceptor(args); + break; + case NATIVE_WINDOW_SET_DEQUEUE_INTERCEPTOR: + res = dispatchAddDequeueInterceptor(args); + break; + case NATIVE_WINDOW_SET_PERFORM_INTERCEPTOR: + res = dispatchAddPerformInterceptor(args); + break; + case NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR: + res = dispatchAddQueueInterceptor(args); + break; + case NATIVE_WINDOW_SET_QUERY_INTERCEPTOR: + res = dispatchAddQueryInterceptor(args); + break; + case NATIVE_WINDOW_ALLOCATE_BUFFERS: + allocateBuffers(); + res = NO_ERROR; + break; + case NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER: + res = dispatchGetLastQueuedBuffer(args); + break; default: res = NAME_NOT_FOUND; break; @@ -1273,13 +1401,119 @@ int Surface::dispatchGetConsumerUsage64(va_list args) { return getConsumerUsage(usage); } +int Surface::dispatchSetAutoPrerotation(va_list args) { + bool autoPrerotation = va_arg(args, int); + return setAutoPrerotation(autoPrerotation); +} + +int Surface::dispatchGetLastDequeueStartTime(va_list args) { + int64_t* lastDequeueStartTime = va_arg(args, int64_t*); + *lastDequeueStartTime = mLastDequeueStartTime; + return NO_ERROR; +} + +int Surface::dispatchSetDequeueTimeout(va_list args) { + nsecs_t timeout = va_arg(args, int64_t); + return setDequeueTimeout(timeout); +} + +int Surface::dispatchGetLastDequeueDuration(va_list args) { + int64_t* lastDequeueDuration = va_arg(args, int64_t*); + *lastDequeueDuration = mLastDequeueDuration; + return NO_ERROR; +} + +int Surface::dispatchGetLastQueueDuration(va_list args) { + int64_t* lastQueueDuration = va_arg(args, int64_t*); + *lastQueueDuration = mLastQueueDuration; + return NO_ERROR; +} + +int Surface::dispatchSetFrameRate(va_list args) { + float frameRate = static_cast<float>(va_arg(args, double)); + int8_t compatibility = static_cast<int8_t>(va_arg(args, int)); + return setFrameRate(frameRate, compatibility); +} + +int Surface::dispatchAddCancelInterceptor(va_list args) { + ANativeWindow_cancelBufferInterceptor interceptor = + va_arg(args, ANativeWindow_cancelBufferInterceptor); + void* data = va_arg(args, void*); + std::lock_guard<std::shared_mutex> lock(mInterceptorMutex); + mCancelInterceptor = interceptor; + mCancelInterceptorData = data; + return NO_ERROR; +} + +int Surface::dispatchAddDequeueInterceptor(va_list args) { + ANativeWindow_dequeueBufferInterceptor interceptor = + va_arg(args, ANativeWindow_dequeueBufferInterceptor); + void* data = va_arg(args, void*); + std::lock_guard<std::shared_mutex> lock(mInterceptorMutex); + mDequeueInterceptor = interceptor; + mDequeueInterceptorData = data; + return NO_ERROR; +} + +int Surface::dispatchAddPerformInterceptor(va_list args) { + ANativeWindow_performInterceptor interceptor = va_arg(args, ANativeWindow_performInterceptor); + void* data = va_arg(args, void*); + std::lock_guard<std::shared_mutex> lock(mInterceptorMutex); + mPerformInterceptor = interceptor; + mPerformInterceptorData = data; + return NO_ERROR; +} + +int Surface::dispatchAddQueueInterceptor(va_list args) { + ANativeWindow_queueBufferInterceptor interceptor = + va_arg(args, ANativeWindow_queueBufferInterceptor); + void* data = va_arg(args, void*); + std::lock_guard<std::shared_mutex> lock(mInterceptorMutex); + mQueueInterceptor = interceptor; + mQueueInterceptorData = data; + return NO_ERROR; +} + +int Surface::dispatchAddQueryInterceptor(va_list args) { + ANativeWindow_queryInterceptor interceptor = va_arg(args, ANativeWindow_queryInterceptor); + void* data = va_arg(args, void*); + std::lock_guard<std::shared_mutex> lock(mInterceptorMutex); + mQueryInterceptor = interceptor; + mQueryInterceptorData = data; + return NO_ERROR; +} + +int Surface::dispatchGetLastQueuedBuffer(va_list args) { + AHardwareBuffer** buffer = va_arg(args, AHardwareBuffer**); + int* fence = va_arg(args, int*); + float* matrix = va_arg(args, float*); + sp<GraphicBuffer> graphicBuffer; + sp<Fence> spFence; + + int result = mGraphicBufferProducer->getLastQueuedBuffer(&graphicBuffer, &spFence, matrix); + + if (graphicBuffer != nullptr) { + *buffer = reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get()); + AHardwareBuffer_acquire(*buffer); + } else { + *buffer = nullptr; + } + + if (spFence != nullptr) { + *fence = spFence->dup(); + } else { + *fence = -1; + } + return result; +} + bool Surface::transformToDisplayInverse() { return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) == NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY; } int Surface::connect(int api) { - static sp<IProducerListener> listener = new DummyProducerListener(); + static sp<IProducerListener> listener = new StubProducerListener(); return connect(api, listener); } @@ -1307,6 +1541,7 @@ int Surface::connect( mDefaultWidth = output.width; mDefaultHeight = output.height; mNextFrameNumber = output.nextFrameNumber; + mMaxBufferCount = output.maxBufferCount; // Ignore transform hint if sticky transform is set or transform to display inverse flag is // set. Transform hint should be ignored if the client is expected to always submit buffers @@ -1348,6 +1583,9 @@ int Surface::disconnect(int api, IGraphicBufferProducer::DisconnectMode mode) { mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; mTransform = 0; mStickyTransform = 0; + mAutoPrerotation = false; + mEnableFrameTimestamps = false; + mMaxBufferCount = NUM_BUFFER_SLOTS; if (api == NATIVE_WINDOW_API_CPU) { mConnectedToCpu = false; @@ -1934,11 +2172,6 @@ int Surface::getConsumerUsage(uint64_t* outUsage) const { return mGraphicBufferProducer->getConsumerUsage(outUsage); } -nsecs_t Surface::getLastDequeueStartTime() const { - Mutex::Autolock lock(mMutex); - return mLastDequeueStartTime; -} - status_t Surface::getAndFlushRemovedBuffers(std::vector<sp<GraphicBuffer>>* out) { if (out == nullptr) { ALOGE("%s: out must not be null!", __FUNCTION__); @@ -1982,6 +2215,24 @@ status_t Surface::attachAndQueueBufferWithDataspace(Surface* surface, sp<Graphic return err; } +int Surface::setAutoPrerotation(bool autoPrerotation) { + ATRACE_CALL(); + ALOGV("Surface::setAutoPrerotation (%d)", autoPrerotation); + Mutex::Autolock lock(mMutex); + + if (mAutoPrerotation == autoPrerotation) { + return OK; + } + + status_t err = mGraphicBufferProducer->setAutoPrerotation(autoPrerotation); + if (err == NO_ERROR) { + mAutoPrerotation = autoPrerotation; + } + ALOGE_IF(err, "IGraphicBufferProducer::setAutoPrerotation(%d) returned %s", autoPrerotation, + strerror(-err)); + return err; +} + void Surface::ProducerListenerProxy::onBuffersDiscarded(const std::vector<int32_t>& slots) { ATRACE_CALL(); sp<Surface> parent = mParent.promote(); @@ -2000,4 +2251,15 @@ void Surface::ProducerListenerProxy::onBuffersDiscarded(const std::vector<int32_ mSurfaceListener->onBuffersDiscarded(discardedBufs); } +status_t Surface::setFrameRate(float frameRate, int8_t compatibility) { + ATRACE_CALL(); + ALOGV("Surface::setFrameRate"); + + if (!ValidateFrameRate(frameRate, compatibility, "Surface::setFrameRate")) { + return BAD_VALUE; + } + + return composerService()->setFrameRate(mGraphicBufferProducer, frameRate, compatibility); +} + }; // namespace android diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index dfc61851c2..83bc06997a 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -31,8 +31,6 @@ #include <system/graphics.h> -#include <ui/DisplayInfo.h> - #include <gui/BufferItemConsumer.h> #include <gui/CpuConsumer.h> #include <gui/IGraphicBufferProducer.h> @@ -41,6 +39,7 @@ #include <gui/LayerState.h> #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> +#include <ui/DisplayConfig.h> #ifndef NO_INPUT #include <input/InputWindow.h> @@ -189,52 +188,84 @@ void TransactionCompletedListener::addSurfaceControlToCallbacks( } void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) { - std::lock_guard<std::mutex> lock(mMutex); + std::unordered_map<CallbackId, CallbackTranslation> callbacksMap; + { + std::lock_guard<std::mutex> lock(mMutex); - /* This listener knows all the sp<IBinder> to sp<SurfaceControl> for all its registered - * callbackIds, except for when Transactions are merged together. This probably cannot be - * solved before this point because the Transactions could be merged together and applied in a - * different process. - * - * Fortunately, we get all the callbacks for this listener for the same frame together at the - * same time. This means if any Transactions were merged together, we will get their callbacks - * at the same time. We can combine all the sp<IBinder> to sp<SurfaceControl> maps for all the - * callbackIds to generate one super map that contains all the sp<IBinder> to sp<SurfaceControl> - * that could possibly exist for the callbacks. - */ - std::unordered_map<sp<IBinder>, sp<SurfaceControl>, IBinderHash> surfaceControls; - for (const auto& transactionStats : listenerStats.transactionStats) { - for (auto callbackId : transactionStats.callbackIds) { - auto& [callbackFunction, callbackSurfaceControls] = mCallbacks[callbackId]; - surfaceControls.insert(callbackSurfaceControls.begin(), callbackSurfaceControls.end()); + /* This listener knows all the sp<IBinder> to sp<SurfaceControl> for all its registered + * callbackIds, except for when Transactions are merged together. This probably cannot be + * solved before this point because the Transactions could be merged together and applied in + * a different process. + * + * Fortunately, we get all the callbacks for this listener for the same frame together at + * the same time. This means if any Transactions were merged together, we will get their + * callbacks at the same time. We can combine all the sp<IBinder> to sp<SurfaceControl> maps + * for all the callbackIds to generate one super map that contains all the sp<IBinder> to + * sp<SurfaceControl> that could possibly exist for the callbacks. + */ + callbacksMap = mCallbacks; + for (const auto& transactionStats : listenerStats.transactionStats) { + for (auto& callbackId : transactionStats.callbackIds) { + mCallbacks.erase(callbackId); + } } } - for (const auto& transactionStats : listenerStats.transactionStats) { for (auto callbackId : transactionStats.callbackIds) { - auto& [callbackFunction, callbackSurfaceControls] = mCallbacks[callbackId]; + auto& [callbackFunction, callbackSurfaceControls] = callbacksMap[callbackId]; if (!callbackFunction) { ALOGE("cannot call null callback function, skipping"); continue; } std::vector<SurfaceControlStats> surfaceControlStats; for (const auto& surfaceStats : transactionStats.surfaceStats) { - surfaceControlStats.emplace_back(surfaceControls[surfaceStats.surfaceControl], - surfaceStats.acquireTime, - surfaceStats.previousReleaseFence); + surfaceControlStats + .emplace_back(callbacksMap[callbackId] + .surfaceControls[surfaceStats.surfaceControl], + transactionStats.latchTime, surfaceStats.acquireTime, + transactionStats.presentFence, + surfaceStats.previousReleaseFence, surfaceStats.transformHint, + surfaceStats.eventStats); + if (callbacksMap[callbackId].surfaceControls[surfaceStats.surfaceControl]) { + callbacksMap[callbackId] + .surfaceControls[surfaceStats.surfaceControl] + ->setTransformHint(surfaceStats.transformHint); + } } callbackFunction(transactionStats.latchTime, transactionStats.presentFence, surfaceControlStats); - mCallbacks.erase(callbackId); } } } // --------------------------------------------------------------------------- -void bufferCacheCallback(void* /*context*/, uint64_t graphicBufferId); - +void removeDeadBufferCallback(void* /*context*/, uint64_t graphicBufferId); + +/** + * We use the BufferCache to reduce the overhead of exchanging GraphicBuffers with + * the server. If we were to simply parcel the GraphicBuffer we would pay two overheads + * 1. Cost of sending the FD + * 2. Cost of importing the GraphicBuffer with the mapper in the receiving process. + * To ease this cost we implement the following scheme of caching buffers to integers, + * or said-otherwise, naming them with integers. This is the scheme known as slots in + * the legacy BufferQueue system. + * 1. When sending Buffers to SurfaceFlinger we look up the Buffer in the cache. + * 2. If there is a cache-hit we remove the Buffer from the Transaction and instead + * send the cached integer. + * 3. If there is a cache miss, we cache the new buffer and send the integer + * along with the Buffer, SurfaceFlinger on it's side creates a new cache + * entry, and we use the integer for further communication. + * A few details about lifetime: + * 1. The cache evicts by LRU. The server side cache is keyed by BufferCache::getToken + * which is per process Unique. The server side cache is larger than the client side + * cache so that the server will never evict entries before the client. + * 2. When the client evicts an entry it notifies the server via an uncacheBuffer + * transaction. + * 3. The client only references the Buffers by ID, and uses buffer->addDeathCallback + * to auto-evict destroyed buffers. + */ class BufferCache : public Singleton<BufferCache> { public: BufferCache() : token(new BBinder()) {} @@ -262,7 +293,7 @@ public: evictLeastRecentlyUsedBuffer(); } - buffer->addDeathCallback(bufferCacheCallback, nullptr); + buffer->addDeathCallback(removeDeadBufferCallback, nullptr); mBuffers[buffer->getId()] = getCounter(); return buffer->getId(); @@ -310,7 +341,7 @@ private: ANDROID_SINGLETON_STATIC_INSTANCE(BufferCache); -void bufferCacheCallback(void* /*context*/, uint64_t graphicBufferId) { +void removeDeadBufferCallback(void* /*context*/, uint64_t graphicBufferId) { // GraphicBuffer id's are used as the cache ids. BufferCache::getInstance().uncache(graphicBufferId); } @@ -322,21 +353,169 @@ SurfaceComposerClient::Transaction::Transaction(const Transaction& other) mTransactionNestCount(other.mTransactionNestCount), mAnimation(other.mAnimation), mEarlyWakeup(other.mEarlyWakeup), + mExplicitEarlyWakeupStart(other.mExplicitEarlyWakeupStart), + mExplicitEarlyWakeupEnd(other.mExplicitEarlyWakeupEnd), + mContainsBuffer(other.mContainsBuffer), mDesiredPresentTime(other.mDesiredPresentTime) { mDisplayStates = other.mDisplayStates; mComposerStates = other.mComposerStates; mInputWindowCommands = other.mInputWindowCommands; + mListenerCallbacks = other.mListenerCallbacks; +} + +std::unique_ptr<SurfaceComposerClient::Transaction> +SurfaceComposerClient::Transaction::createFromParcel(const Parcel* parcel) { + auto transaction = std::make_unique<Transaction>(); + if (transaction->readFromParcel(parcel) == NO_ERROR) { + return transaction; + } + return nullptr; +} + +status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel) { + const uint32_t forceSynchronous = parcel->readUint32(); + const uint32_t transactionNestCount = parcel->readUint32(); + const bool animation = parcel->readBool(); + const bool earlyWakeup = parcel->readBool(); + const bool explicitEarlyWakeupStart = parcel->readBool(); + const bool explicitEarlyWakeupEnd = parcel->readBool(); + const bool containsBuffer = parcel->readBool(); + const int64_t desiredPresentTime = parcel->readInt64(); + + size_t count = static_cast<size_t>(parcel->readUint32()); + if (count > parcel->dataSize()) { + return BAD_VALUE; + } + SortedVector<DisplayState> displayStates; + displayStates.setCapacity(count); + for (size_t i = 0; i < count; i++) { + DisplayState displayState; + if (displayState.read(*parcel) == BAD_VALUE) { + return BAD_VALUE; + } + displayStates.add(displayState); + } + + count = static_cast<size_t>(parcel->readUint32()); + if (count > parcel->dataSize()) { + return BAD_VALUE; + } + std::unordered_map<sp<ITransactionCompletedListener>, CallbackInfo, TCLHash> listenerCallbacks; + listenerCallbacks.reserve(count); + for (size_t i = 0; i < count; i++) { + sp<ITransactionCompletedListener> listener = + interface_cast<ITransactionCompletedListener>(parcel->readStrongBinder()); + size_t numCallbackIds = parcel->readUint32(); + if (numCallbackIds > parcel->dataSize()) { + return BAD_VALUE; + } + for (size_t j = 0; j < numCallbackIds; j++) { + listenerCallbacks[listener].callbackIds.insert(parcel->readInt64()); + } + size_t numSurfaces = parcel->readUint32(); + if (numSurfaces > parcel->dataSize()) { + return BAD_VALUE; + } + for (size_t j = 0; j < numSurfaces; j++) { + sp<SurfaceControl> surface; + surface = SurfaceControl::readFromParcel(parcel); + listenerCallbacks[listener].surfaceControls.insert(surface); + } + } + + count = static_cast<size_t>(parcel->readUint32()); + if (count > parcel->dataSize()) { + return BAD_VALUE; + } + std::unordered_map<sp<IBinder>, ComposerState, IBinderHash> composerStates; + composerStates.reserve(count); + for (size_t i = 0; i < count; i++) { + sp<IBinder> surfaceControlHandle = parcel->readStrongBinder(); + + ComposerState composerState; + if (composerState.read(*parcel) == BAD_VALUE) { + return BAD_VALUE; + } + composerStates[surfaceControlHandle] = composerState; + } + + InputWindowCommands inputWindowCommands; + inputWindowCommands.read(*parcel); + + // Parsing was successful. Update the object. + mForceSynchronous = forceSynchronous; + mTransactionNestCount = transactionNestCount; + mAnimation = animation; + mEarlyWakeup = earlyWakeup; + mExplicitEarlyWakeupStart = explicitEarlyWakeupStart; + mExplicitEarlyWakeupEnd = explicitEarlyWakeupEnd; + mContainsBuffer = containsBuffer; + mDesiredPresentTime = desiredPresentTime; + mDisplayStates = displayStates; + mListenerCallbacks = listenerCallbacks; + mComposerStates = composerStates; + mInputWindowCommands = inputWindowCommands; + return NO_ERROR; +} + +status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const { + // If we write the Transaction to a parcel, we want to ensure the Buffers are cached + // before crossing the IPC boundary. Otherwise the receiving party will cache the buffers + // but is unlikely to use them again as they are owned by the other process. + // You may be asking yourself, is this const cast safe? Const cast is safe up + // until the point where you try and write to an object that was originally const at which + // point we enter undefined behavior. In this case we are safe though, because there are + // two possibilities: + // 1. The SurfaceComposerClient::Transaction was originally non-const. Safe. + // 2. It was originall const! In this case not only was it useless, but it by definition + // contains no composer states and so cacheBuffers will not perform any writes. + + const_cast<SurfaceComposerClient::Transaction*>(this)->cacheBuffers(); + + parcel->writeUint32(mForceSynchronous); + parcel->writeUint32(mTransactionNestCount); + parcel->writeBool(mAnimation); + parcel->writeBool(mEarlyWakeup); + parcel->writeBool(mExplicitEarlyWakeupStart); + parcel->writeBool(mExplicitEarlyWakeupEnd); + parcel->writeBool(mContainsBuffer); + parcel->writeInt64(mDesiredPresentTime); + parcel->writeUint32(static_cast<uint32_t>(mDisplayStates.size())); + for (auto const& displayState : mDisplayStates) { + displayState.write(*parcel); + } + + parcel->writeUint32(static_cast<uint32_t>(mListenerCallbacks.size())); + for (auto const& [listener, callbackInfo] : mListenerCallbacks) { + parcel->writeStrongBinder(ITransactionCompletedListener::asBinder(listener)); + parcel->writeUint32(static_cast<uint32_t>(callbackInfo.callbackIds.size())); + for (auto callbackId : callbackInfo.callbackIds) { + parcel->writeInt64(callbackId); + } + parcel->writeUint32(static_cast<uint32_t>(callbackInfo.surfaceControls.size())); + for (auto surfaceControl : callbackInfo.surfaceControls) { + surfaceControl->writeToParcel(parcel); + } + } + + parcel->writeUint32(static_cast<uint32_t>(mComposerStates.size())); + for (auto const& [surfaceHandle, composerState] : mComposerStates) { + parcel->writeStrongBinder(surfaceHandle); + composerState.write(*parcel); + } + + mInputWindowCommands.write(*parcel); + return NO_ERROR; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) { - for (auto const& kv : other.mComposerStates) { - if (mComposerStates.count(kv.first) == 0) { - mComposerStates[kv.first] = kv.second; + for (auto const& [surfaceHandle, composerState] : other.mComposerStates) { + if (mComposerStates.count(surfaceHandle) == 0) { + mComposerStates[surfaceHandle] = composerState; } else { - mComposerStates[kv.first].state.merge(kv.second.state); + mComposerStates[surfaceHandle].state.merge(composerState.state); } } - other.mComposerStates.clear(); for (auto const& state : other.mDisplayStates) { ssize_t index = mDisplayStates.indexOf(state); @@ -346,46 +525,53 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr mDisplayStates.editItemAt(static_cast<size_t>(index)).merge(state); } } - other.mDisplayStates.clear(); for (const auto& [listener, callbackInfo] : other.mListenerCallbacks) { auto& [callbackIds, surfaceControls] = callbackInfo; mListenerCallbacks[listener].callbackIds.insert(std::make_move_iterator( callbackIds.begin()), std::make_move_iterator(callbackIds.end())); - mListenerCallbacks[listener] - .surfaceControls.insert(std::make_move_iterator(surfaceControls.begin()), - std::make_move_iterator(surfaceControls.end())); + + mListenerCallbacks[listener].surfaceControls.insert(surfaceControls.begin(), + surfaceControls.end()); + + auto& currentProcessCallbackInfo = + mListenerCallbacks[TransactionCompletedListener::getIInstance()]; + currentProcessCallbackInfo.surfaceControls + .insert(std::make_move_iterator(surfaceControls.begin()), + std::make_move_iterator(surfaceControls.end())); + + // register all surface controls for all callbackIds for this listener that is merging + for (const auto& surfaceControl : currentProcessCallbackInfo.surfaceControls) { + TransactionCompletedListener::getInstance() + ->addSurfaceControlToCallbacks(surfaceControl, + currentProcessCallbackInfo.callbackIds); + } } - other.mListenerCallbacks.clear(); mInputWindowCommands.merge(other.mInputWindowCommands); - other.mInputWindowCommands.clear(); - - mContainsBuffer = other.mContainsBuffer; - other.mContainsBuffer = false; + mContainsBuffer |= other.mContainsBuffer; mEarlyWakeup = mEarlyWakeup || other.mEarlyWakeup; - other.mEarlyWakeup = false; - + mExplicitEarlyWakeupStart = mExplicitEarlyWakeupStart || other.mExplicitEarlyWakeupStart; + mExplicitEarlyWakeupEnd = mExplicitEarlyWakeupEnd || other.mExplicitEarlyWakeupEnd; + other.clear(); return *this; } -void SurfaceComposerClient::doDropReferenceTransaction(const sp<IBinder>& handle, - const sp<ISurfaceComposerClient>& client) { - sp<ISurfaceComposer> sf(ComposerService::getComposerService()); - Vector<ComposerState> composerStates; - Vector<DisplayState> displayStates; - - ComposerState s; - s.client = client; - s.state.surface = handle; - s.state.what |= layer_state_t::eReparent; - s.state.parentHandleForChild = nullptr; - - composerStates.add(s); - sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); - sf->setTransactionState(composerStates, displayStates, 0, applyToken, {}, -1, {}, {}); +void SurfaceComposerClient::Transaction::clear() { + mComposerStates.clear(); + mDisplayStates.clear(); + mListenerCallbacks.clear(); + mInputWindowCommands.clear(); + mContainsBuffer = false; + mForceSynchronous = 0; + mTransactionNestCount = 0; + mAnimation = false; + mEarlyWakeup = false; + mExplicitEarlyWakeupStart = false; + mExplicitEarlyWakeupEnd = false; + mDesiredPresentTime = -1; } void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) { @@ -396,7 +582,7 @@ void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) { uncacheBuffer.id = cacheId; sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); - sf->setTransactionState({}, {}, 0, applyToken, {}, -1, uncacheBuffer, {}); + sf->setTransactionState({}, {}, 0, applyToken, {}, -1, uncacheBuffer, false, {}); } void SurfaceComposerClient::Transaction::cacheBuffers() { @@ -405,10 +591,15 @@ void SurfaceComposerClient::Transaction::cacheBuffers() { } size_t count = 0; - for (auto& [sc, cs] : mComposerStates) { - layer_state_t* s = getLayerState(sc); + for (auto& [handle, cs] : mComposerStates) { + layer_state_t* s = getLayerState(handle); if (!(s->what & layer_state_t::eBufferChanged)) { continue; + } else if (s->what & layer_state_t::eCachedBufferChanged) { + // If eBufferChanged and eCachedBufferChanged are both trued then that means + // we already cached the buffer in a previous call to cacheBuffers, perhaps + // from writeToParcel on a Transaction that was merged in to this one. + continue; } // Don't try to cache a null buffer. Sending null buffers is cheap so we shouldn't waste @@ -420,9 +611,11 @@ void SurfaceComposerClient::Transaction::cacheBuffers() { uint64_t cacheId = 0; status_t ret = BufferCache::getInstance().getCacheId(s->buffer, &cacheId); if (ret == NO_ERROR) { + // Cache-hit. Strip the buffer and send only the id. s->what &= ~static_cast<uint64_t>(layer_state_t::eBufferChanged); s->buffer = nullptr; } else { + // Cache-miss. Include the buffer and send the new cacheId. cacheId = BufferCache::getInstance().cache(s->buffer); } s->what |= layer_state_t::eCachedBufferChanged; @@ -445,8 +638,8 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous) { sp<ISurfaceComposer> sf(ComposerService::getComposerService()); + bool hasListenerCallbacks = !mListenerCallbacks.empty(); std::vector<ListenerCallbacks> listenerCallbacks; - // For every listener with registered callbacks for (const auto& [listener, callbackInfo] : mListenerCallbacks) { auto& [callbackIds, surfaceControls] = callbackInfo; @@ -454,19 +647,24 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous) { continue; } - listenerCallbacks.emplace_back(listener, std::move(callbackIds)); - - // If the listener has any SurfaceControls set on this Transaction update the surface state - for (const auto& surfaceControl : surfaceControls) { - layer_state_t* s = getLayerState(surfaceControl); - if (!s) { - ALOGE("failed to get layer state"); - continue; + if (surfaceControls.empty()) { + listenerCallbacks.emplace_back(IInterface::asBinder(listener), std::move(callbackIds)); + } else { + // If the listener has any SurfaceControls set on this Transaction update the surface + // state + for (const auto& surfaceControl : surfaceControls) { + layer_state_t* s = getLayerState(surfaceControl); + if (!s) { + ALOGE("failed to get layer state"); + continue; + } + std::vector<CallbackId> callbacks(callbackIds.begin(), callbackIds.end()); + s->what |= layer_state_t::eHasListenerCallbacksChanged; + s->listeners.emplace_back(IInterface::asBinder(listener), callbacks); } - s->what |= layer_state_t::eHasListenerCallbacksChanged; - s->hasListenerCallbacks = true; } } + mListenerCallbacks.clear(); cacheBuffers(); @@ -496,15 +694,26 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous) { flags |= ISurfaceComposer::eEarlyWakeup; } + // If both mExplicitEarlyWakeupStart and mExplicitEarlyWakeupEnd are set + // it is equivalent for none + if (mExplicitEarlyWakeupStart && !mExplicitEarlyWakeupEnd) { + flags |= ISurfaceComposer::eExplicitEarlyWakeupStart; + } + if (mExplicitEarlyWakeupEnd && !mExplicitEarlyWakeupStart) { + flags |= ISurfaceComposer::eExplicitEarlyWakeupEnd; + } + mForceSynchronous = false; mAnimation = false; mEarlyWakeup = false; + mExplicitEarlyWakeupStart = false; + mExplicitEarlyWakeupEnd = false; sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); sf->setTransactionState(composerStates, displayStates, flags, applyToken, mInputWindowCommands, mDesiredPresentTime, {} /*uncacheBuffer - only set in doUncacheBufferTransaction*/, - listenerCallbacks); + hasListenerCallbacks, listenerCallbacks); mInputWindowCommands.clear(); mStatus = NO_ERROR; return NO_ERROR; @@ -545,16 +754,23 @@ void SurfaceComposerClient::Transaction::setEarlyWakeup() { mEarlyWakeup = true; } -layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<SurfaceControl>& sc) { - if (mComposerStates.count(sc) == 0) { +void SurfaceComposerClient::Transaction::setExplicitEarlyWakeupStart() { + mExplicitEarlyWakeupStart = true; +} + +void SurfaceComposerClient::Transaction::setExplicitEarlyWakeupEnd() { + mExplicitEarlyWakeupEnd = true; +} + +layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<IBinder>& handle) { + if (mComposerStates.count(handle) == 0) { // we don't have it, add an initialized layer_state to our list ComposerState s; - s.client = sc->getClient()->mClient; - s.state.surface = sc->getHandle(); - mComposerStates[sc] = s; + s.state.surface = handle; + mComposerStates[handle] = s; } - return &(mComposerStates[sc].state); + return &(mComposerStates[handle].state); } void SurfaceComposerClient::Transaction::registerSurfaceControlForCallback( @@ -626,6 +842,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setRelat layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; + return *this; } s->what |= layer_state_t::eRelativeLayerChanged; s->what &= ~layer_state_t::eLayerChanged; @@ -761,6 +978,18 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCorne return *this; } +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBackgroundBlurRadius( + const sp<SurfaceControl>& sc, int backgroundBlurRadius) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + s->what |= layer_state_t::eBackgroundBlurRadiusChanged; + s->backgroundBlurRadius = backgroundBlurRadius; + return *this; +} + SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::deferTransactionUntil_legacy(const sp<SurfaceControl>& sc, const sp<IBinder>& handle, @@ -1035,6 +1264,22 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColor } SurfaceComposerClient::Transaction& +SurfaceComposerClient::Transaction::setFrameRateSelectionPriority(const sp<SurfaceControl>& sc, + int32_t priority) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + + s->what |= layer_state_t::eFrameRateSelectionPriority; + s->frameRateSelectionPriority = priority; + + registerSurfaceControlForCallback(sc); + return *this; +} + +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::addTransactionCompletedCallback( TransactionCompletedCallbackTakesContext callback, void* callbackContext) { auto listener = TransactionCompletedListener::getInstance(); @@ -1051,11 +1296,24 @@ SurfaceComposerClient::Transaction::addTransactionCompletedCallback( return *this; } +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::notifyProducerDisconnect( + const sp<SurfaceControl>& sc) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + + s->what |= layer_state_t::eProducerDisconnect; + return *this; +} + SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::detachChildren( const sp<SurfaceControl>& sc) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; + return *this; } s->what |= layer_state_t::eDetachChildren; @@ -1092,19 +1350,6 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setOverr return *this; } -SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setGeometryAppliesWithResize( - const sp<SurfaceControl>& sc) { - layer_state_t* s = getLayerState(sc); - if (!s) { - mStatus = BAD_INDEX; - return *this; - } - s->what |= layer_state_t::eGeometryAppliesWithResize; - - registerSurfaceControlForCallback(sc); - return *this; -} - #ifndef NO_INPUT SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setInputWindowInfo( const sp<SurfaceControl>& sc, @@ -1119,15 +1364,6 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setInput return *this; } -SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::transferTouchFocus( - const sp<IBinder>& fromToken, const sp<IBinder>& toToken) { - InputWindowCommands::TransferTouchFocusCommand transferTouchFocusCommand; - transferTouchFocusCommand.fromToken = fromToken; - transferTouchFocusCommand.toToken = toToken; - mInputWindowCommands.transferTouchFocusCommands.emplace_back(transferTouchFocusCommand); - return *this; -} - SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::syncInputWindows() { mInputWindowCommands.syncInputWindows = true; return *this; @@ -1196,8 +1432,55 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setGeome break; } setMatrix(sc, matrix[0], matrix[1], matrix[2], matrix[3]); - setPosition(sc, x, y); + float offsetX = xScale * source.left; + float offsetY = yScale * source.top; + setPosition(sc, x - offsetX, y - offsetY); + + return *this; +} + +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setShadowRadius( + const sp<SurfaceControl>& sc, float shadowRadius) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + s->what |= layer_state_t::eShadowRadiusChanged; + s->shadowRadius = shadowRadius; + return *this; +} + +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameRate( + const sp<SurfaceControl>& sc, float frameRate, int8_t compatibility) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + if (!ValidateFrameRate(frameRate, compatibility, "Transaction::setFrameRate")) { + mStatus = BAD_VALUE; + return *this; + } + s->what |= layer_state_t::eFrameRateChanged; + s->frameRate = frameRate; + s->frameRateCompatibility = compatibility; + return *this; +} + +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFixedTransformHint( + const sp<SurfaceControl>& sc, int32_t fixedTransformHint) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + const ui::Transform::RotationFlags transform = fixedTransformHint == -1 + ? ui::Transform::ROT_INVALID + : ui::Transform::toRotationFlags(static_cast<ui::Rotation>(fixedTransformHint)); + s->what |= layer_state_t::eFixedTransformHintChanged; + s->fixedTransformHint = transform; return *this; } @@ -1242,9 +1525,9 @@ void SurfaceComposerClient::Transaction::setDisplayLayerStack(const sp<IBinder>& } void SurfaceComposerClient::Transaction::setDisplayProjection(const sp<IBinder>& token, - uint32_t orientation, - const Rect& layerStackRect, - const Rect& displayRect) { + ui::Rotation orientation, + const Rect& layerStackRect, + const Rect& displayRect) { DisplayState& s(getDisplayState(token)); s.orientation = orientation; s.viewport = layerStackRect; @@ -1317,16 +1600,19 @@ void SurfaceComposerClient::dispose() { sp<SurfaceControl> SurfaceComposerClient::createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags, SurfaceControl* parent, - LayerMetadata metadata) { + LayerMetadata metadata, + uint32_t* outTransformHint) { sp<SurfaceControl> s; - createSurfaceChecked(name, w, h, format, &s, flags, parent, std::move(metadata)); + createSurfaceChecked(name, w, h, format, &s, flags, parent, std::move(metadata), + outTransformHint); return s; } sp<SurfaceControl> SurfaceComposerClient::createWithSurfaceParent(const String8& name, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags, Surface* parent, - LayerMetadata metadata) { + LayerMetadata metadata, + uint32_t* outTransformHint) { sp<SurfaceControl> sur; status_t err = mStatus; @@ -1335,11 +1621,15 @@ sp<SurfaceControl> SurfaceComposerClient::createWithSurfaceParent(const String8& sp<IGraphicBufferProducer> parentGbp = parent->getIGraphicBufferProducer(); sp<IGraphicBufferProducer> gbp; + uint32_t transformHint = 0; err = mClient->createWithSurfaceParent(name, w, h, format, flags, parentGbp, - std::move(metadata), &handle, &gbp); + std::move(metadata), &handle, &gbp, &transformHint); + if (outTransformHint) { + *outTransformHint = transformHint; + } ALOGE_IF(err, "SurfaceComposerClient::createWithSurfaceParent error %s", strerror(-err)); if (err == NO_ERROR) { - return new SurfaceControl(this, handle, gbp, true /* owned */); + return new SurfaceControl(this, handle, gbp, transformHint); } } return nullptr; @@ -1348,8 +1638,8 @@ sp<SurfaceControl> SurfaceComposerClient::createWithSurfaceParent(const String8& status_t SurfaceComposerClient::createSurfaceChecked(const String8& name, uint32_t w, uint32_t h, PixelFormat format, sp<SurfaceControl>* outSurface, uint32_t flags, - SurfaceControl* parent, - LayerMetadata metadata) { + SurfaceControl* parent, LayerMetadata metadata, + uint32_t* outTransformHint) { sp<SurfaceControl> sur; status_t err = mStatus; @@ -1362,16 +1652,34 @@ status_t SurfaceComposerClient::createSurfaceChecked(const String8& name, uint32 parentHandle = parent->getHandle(); } + uint32_t transformHint = 0; err = mClient->createSurface(name, w, h, format, flags, parentHandle, std::move(metadata), - &handle, &gbp); + &handle, &gbp, &transformHint); + if (outTransformHint) { + *outTransformHint = transformHint; + } ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err)); if (err == NO_ERROR) { - *outSurface = new SurfaceControl(this, handle, gbp, true /* owned */); + *outSurface = new SurfaceControl(this, handle, gbp, transformHint); } } return err; } +sp<SurfaceControl> SurfaceComposerClient::mirrorSurface(SurfaceControl* mirrorFromSurface) { + if (mirrorFromSurface == nullptr) { + return nullptr; + } + + sp<IBinder> handle; + sp<IBinder> mirrorFromHandle = mirrorFromSurface->getHandle(); + status_t err = mClient->mirrorSurface(mirrorFromHandle, &handle); + if (err == NO_ERROR) { + return new SurfaceControl(this, handle, nullptr, true /* owned */); + } + return nullptr; +} + status_t SurfaceComposerClient::clearLayerFrameStats(const sp<IBinder>& token) const { if (mStatus != NO_ERROR) { return mStatus; @@ -1399,15 +1707,23 @@ status_t SurfaceComposerClient::injectVSync(nsecs_t when) { return sf->injectVSync(when); } -status_t SurfaceComposerClient::getDisplayConfigs( - const sp<IBinder>& display, Vector<DisplayInfo>* configs) -{ +status_t SurfaceComposerClient::getDisplayState(const sp<IBinder>& display, + ui::DisplayState* state) { + return ComposerService::getComposerService()->getDisplayState(display, state); +} + +status_t SurfaceComposerClient::getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info) { + return ComposerService::getComposerService()->getDisplayInfo(display, info); +} + +status_t SurfaceComposerClient::getDisplayConfigs(const sp<IBinder>& display, + Vector<DisplayConfig>* configs) { return ComposerService::getComposerService()->getDisplayConfigs(display, configs); } -status_t SurfaceComposerClient::getDisplayInfo(const sp<IBinder>& display, - DisplayInfo* info) { - Vector<DisplayInfo> configs; +status_t SurfaceComposerClient::getActiveDisplayConfig(const sp<IBinder>& display, + DisplayConfig* config) { + Vector<DisplayConfig> configs; status_t result = getDisplayConfigs(display, &configs); if (result != NO_ERROR) { return result; @@ -1419,7 +1735,7 @@ status_t SurfaceComposerClient::getDisplayInfo(const sp<IBinder>& display, return NAME_NOT_FOUND; } - *info = configs[static_cast<size_t>(activeId)]; + *config = configs[static_cast<size_t>(activeId)]; return NO_ERROR; } @@ -1427,20 +1743,28 @@ int SurfaceComposerClient::getActiveConfig(const sp<IBinder>& display) { return ComposerService::getComposerService()->getActiveConfig(display); } -status_t SurfaceComposerClient::setActiveConfig(const sp<IBinder>& display, int id) { - return ComposerService::getComposerService()->setActiveConfig(display, id); -} - -status_t SurfaceComposerClient::setAllowedDisplayConfigs( - const sp<IBinder>& displayToken, const std::vector<int32_t>& allowedConfigs) { - return ComposerService::getComposerService()->setAllowedDisplayConfigs(displayToken, - allowedConfigs); +status_t SurfaceComposerClient::setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken, + int32_t defaultConfig, + float primaryRefreshRateMin, + float primaryRefreshRateMax, + float appRequestRefreshRateMin, + float appRequestRefreshRateMax) { + return ComposerService::getComposerService() + ->setDesiredDisplayConfigSpecs(displayToken, defaultConfig, primaryRefreshRateMin, + primaryRefreshRateMax, appRequestRefreshRateMin, + appRequestRefreshRateMax); } -status_t SurfaceComposerClient::getAllowedDisplayConfigs(const sp<IBinder>& displayToken, - std::vector<int32_t>* outAllowedConfigs) { - return ComposerService::getComposerService()->getAllowedDisplayConfigs(displayToken, - outAllowedConfigs); +status_t SurfaceComposerClient::getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken, + int32_t* outDefaultConfig, + float* outPrimaryRefreshRateMin, + float* outPrimaryRefreshRateMax, + float* outAppRequestRefreshRateMin, + float* outAppRequestRefreshRateMax) { + return ComposerService::getComposerService() + ->getDesiredDisplayConfigSpecs(displayToken, outDefaultConfig, outPrimaryRefreshRateMin, + outPrimaryRefreshRateMax, outAppRequestRefreshRateMin, + outAppRequestRefreshRateMax); } status_t SurfaceComposerClient::getDisplayColorModes(const sp<IBinder>& display, @@ -1462,6 +1786,26 @@ status_t SurfaceComposerClient::setActiveColorMode(const sp<IBinder>& display, return ComposerService::getComposerService()->setActiveColorMode(display, colorMode); } +bool SurfaceComposerClient::getAutoLowLatencyModeSupport(const sp<IBinder>& display) { + bool supported = false; + ComposerService::getComposerService()->getAutoLowLatencyModeSupport(display, &supported); + return supported; +} + +void SurfaceComposerClient::setAutoLowLatencyMode(const sp<IBinder>& display, bool on) { + ComposerService::getComposerService()->setAutoLowLatencyMode(display, on); +} + +bool SurfaceComposerClient::getGameContentTypeSupport(const sp<IBinder>& display) { + bool supported = false; + ComposerService::getComposerService()->getGameContentTypeSupport(display, &supported); + return supported; +} + +void SurfaceComposerClient::setGameContentType(const sp<IBinder>& display, bool on) { + ComposerService::getComposerService()->setGameContentType(display, on); +} + void SurfaceComposerClient::setDisplayPowerMode(const sp<IBinder>& token, int mode) { ComposerService::getComposerService()->setPowerMode(token, mode); @@ -1553,30 +1897,36 @@ status_t SurfaceComposerClient::notifyPowerHint(int32_t hintId) { return ComposerService::getComposerService()->notifyPowerHint(hintId); } +status_t SurfaceComposerClient::setGlobalShadowSettings(const half4& ambientColor, + const half4& spotColor, float lightPosY, + float lightPosZ, float lightRadius) { + return ComposerService::getComposerService()->setGlobalShadowSettings(ambientColor, spotColor, + lightPosY, lightPosZ, + lightRadius); +} + // ---------------------------------------------------------------------------- -status_t ScreenshotClient::capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace, - const ui::PixelFormat reqPixelFormat, Rect sourceCrop, +status_t ScreenshotClient::capture(const sp<IBinder>& display, ui::Dataspace reqDataSpace, + ui::PixelFormat reqPixelFormat, const Rect& sourceCrop, uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform, - uint32_t rotation, bool captureSecureLayers, + ui::Rotation rotation, bool captureSecureLayers, sp<GraphicBuffer>* outBuffer, bool& outCapturedSecureLayers) { sp<ISurfaceComposer> s(ComposerService::getComposerService()); if (s == nullptr) return NO_INIT; - status_t ret = - s->captureScreen(display, outBuffer, outCapturedSecureLayers, reqDataSpace, - reqPixelFormat, sourceCrop, reqWidth, reqHeight, useIdentityTransform, - static_cast<ISurfaceComposer::Rotation>(rotation), - captureSecureLayers); + status_t ret = s->captureScreen(display, outBuffer, outCapturedSecureLayers, reqDataSpace, + reqPixelFormat, sourceCrop, reqWidth, reqHeight, + useIdentityTransform, rotation, captureSecureLayers); if (ret != NO_ERROR) { return ret; } return ret; } -status_t ScreenshotClient::capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace, - const ui::PixelFormat reqPixelFormat, Rect sourceCrop, +status_t ScreenshotClient::capture(const sp<IBinder>& display, ui::Dataspace reqDataSpace, + ui::PixelFormat reqPixelFormat, const Rect& sourceCrop, uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform, - uint32_t rotation, sp<GraphicBuffer>* outBuffer) { + ui::Rotation rotation, sp<GraphicBuffer>* outBuffer) { bool ignored; return capture(display, reqDataSpace, reqPixelFormat, sourceCrop, reqWidth, reqHeight, useIdentityTransform, rotation, false, outBuffer, ignored); @@ -1589,9 +1939,8 @@ status_t ScreenshotClient::capture(uint64_t displayOrLayerStack, ui::Dataspace* return s->captureScreen(displayOrLayerStack, outDataspace, outBuffer); } -status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle, - const ui::Dataspace reqDataSpace, - const ui::PixelFormat reqPixelFormat, Rect sourceCrop, +status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle, ui::Dataspace reqDataSpace, + ui::PixelFormat reqPixelFormat, const Rect& sourceCrop, float frameScale, sp<GraphicBuffer>* outBuffer) { sp<ISurfaceComposer> s(ComposerService::getComposerService()); if (s == nullptr) return NO_INIT; @@ -1601,8 +1950,8 @@ status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle, } status_t ScreenshotClient::captureChildLayers( - const sp<IBinder>& layerHandle, const ui::Dataspace reqDataSpace, - const ui::PixelFormat reqPixelFormat, Rect sourceCrop, + const sp<IBinder>& layerHandle, ui::Dataspace reqDataSpace, ui::PixelFormat reqPixelFormat, + const Rect& sourceCrop, const std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>>& excludeHandles, float frameScale, sp<GraphicBuffer>* outBuffer) { sp<ISurfaceComposer> s(ComposerService::getComposerService()); @@ -1612,5 +1961,5 @@ status_t ScreenshotClient::captureChildLayers( excludeHandles, frameScale, true /* childrenOnly */); return ret; } -// ---------------------------------------------------------------------------- -}; // namespace android + +} // namespace android diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp index 55488dad0b..a332a1f2a8 100644 --- a/libs/gui/SurfaceControl.cpp +++ b/libs/gui/SurfaceControl.cpp @@ -45,42 +45,23 @@ namespace android { // SurfaceControl // ============================================================================ -SurfaceControl::SurfaceControl( - const sp<SurfaceComposerClient>& client, - const sp<IBinder>& handle, - const sp<IGraphicBufferProducer>& gbp, - bool owned) - : mClient(client), mHandle(handle), mGraphicBufferProducer(gbp), mOwned(owned) -{ -} +SurfaceControl::SurfaceControl(const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle, + const sp<IGraphicBufferProducer>& gbp, + uint32_t transform) + : mClient(client), + mHandle(handle), + mGraphicBufferProducer(gbp), + mTransformHint(transform) {} SurfaceControl::SurfaceControl(const sp<SurfaceControl>& other) { mClient = other->mClient; mHandle = other->mHandle; mGraphicBufferProducer = other->mGraphicBufferProducer; - mOwned = false; + mTransformHint = other->mTransformHint; } SurfaceControl::~SurfaceControl() { - // Avoid reparenting the server-side surface to null if we are not the owner of it, - // meaning that we retrieved it from another process. - if (mClient != nullptr && mHandle != nullptr && mOwned) { - SurfaceComposerClient::doDropReferenceTransaction(mHandle, mClient->getClient()); - } - release(); -} - -void SurfaceControl::destroy() -{ - if (isValid()) { - SurfaceComposerClient::Transaction().reparent(this, nullptr).apply(); - } - release(); -} - -void SurfaceControl::release() -{ // Trigger an IPC now, to make sure things // happen without delay, since these resources are quite heavy. mClient.clear(); @@ -164,7 +145,6 @@ sp<Surface> SurfaceControl::createSurface() const sp<IBinder> SurfaceControl::getHandle() const { - Mutex::Autolock lock(mLock); return mHandle; } @@ -179,15 +159,25 @@ sp<SurfaceComposerClient> SurfaceControl::getClient() const return mClient; } +uint32_t SurfaceControl::getTransformHint() const { + Mutex::Autolock _l(mLock); + return mTransformHint; +} + +void SurfaceControl::setTransformHint(uint32_t hint) { + Mutex::Autolock _l(mLock); + mTransformHint = hint; +} + void SurfaceControl::writeToParcel(Parcel* parcel) { parcel->writeStrongBinder(ISurfaceComposerClient::asBinder(mClient->getClient())); parcel->writeStrongBinder(mHandle); parcel->writeStrongBinder(IGraphicBufferProducer::asBinder(mGraphicBufferProducer)); + parcel->writeUint32(mTransformHint); } -sp<SurfaceControl> SurfaceControl::readFromParcel(Parcel* parcel) -{ +sp<SurfaceControl> SurfaceControl::readFromParcel(const Parcel* parcel) { sp<IBinder> client = parcel->readStrongBinder(); sp<IBinder> handle = parcel->readStrongBinder(); if (client == nullptr || handle == nullptr) @@ -198,10 +188,12 @@ sp<SurfaceControl> SurfaceControl::readFromParcel(Parcel* parcel) sp<IBinder> gbp; parcel->readNullableStrongBinder(&gbp); + uint32_t transformHint = parcel->readUint32(); // We aren't the original owner of the surface. return new SurfaceControl(new SurfaceComposerClient( - interface_cast<ISurfaceComposerClient>(client)), - handle.get(), interface_cast<IGraphicBufferProducer>(gbp), false /* owned */); + interface_cast<ISurfaceComposerClient>(client)), + handle.get(), interface_cast<IGraphicBufferProducer>(gbp), + transformHint); } // ---------------------------------------------------------------------------- diff --git a/libs/gui/TEST_MAPPING b/libs/gui/TEST_MAPPING new file mode 100644 index 0000000000..1c435304a8 --- /dev/null +++ b/libs/gui/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "imports": [ + { + "path": "frameworks/native/libs/nativewindow" + } + ] +} diff --git a/libs/gui/bufferqueue/1.0/Conversion.cpp b/libs/gui/bufferqueue/1.0/Conversion.cpp index 5cb35933e9..3e20a37d54 100644 --- a/libs/gui/bufferqueue/1.0/Conversion.cpp +++ b/libs/gui/bufferqueue/1.0/Conversion.cpp @@ -109,20 +109,6 @@ status_t toStatusT(Return<void> const& t) { } /** - * \brief Convert `Return<void>` to `binder::Status`. - * - * \param[in] t The source `Return<void>`. - * \return The corresponding `binder::Status`. - */ -// convert: Return<void> -> ::android::binder::Status -::android::binder::Status toBinderStatus( - Return<void> const& t) { - return ::android::binder::Status::fromExceptionCode( - toStatusT(t), - t.description().c_str()); -} - -/** * \brief Wrap `native_handle_t*` in `hidl_handle`. * * \param[in] nh The source `native_handle_t*`. @@ -1337,57 +1323,6 @@ status_t unflatten( return unflatten(&(t->surfaceDamage), buffer, size); } -/** - * \brief Wrap `BGraphicBufferProducer::QueueBufferInput` in - * `HGraphicBufferProducer::QueueBufferInput`. - * - * \param[out] t The wrapper of type - * `HGraphicBufferProducer::QueueBufferInput`. - * \param[out] nh The underlying native handle for `t->fence`. - * \param[in] l The source `BGraphicBufferProducer::QueueBufferInput`. - * - * If the return value is `true` and `t->fence` contains a valid file - * descriptor, \p nh will be a newly created native handle holding that file - * descriptor. \p nh needs to be deleted with `native_handle_delete()` - * afterwards. - */ -bool wrapAs( - HGraphicBufferProducer::QueueBufferInput* t, - native_handle_t** nh, - BGraphicBufferProducer::QueueBufferInput const& l) { - - size_t const baseSize = l.getFlattenedSize(); - std::unique_ptr<uint8_t[]> baseBuffer( - new (std::nothrow) uint8_t[baseSize]); - if (!baseBuffer) { - return false; - } - - size_t const baseNumFds = l.getFdCount(); - std::unique_ptr<int[]> baseFds( - new (std::nothrow) int[baseNumFds]); - if (!baseFds) { - return false; - } - - void* buffer = static_cast<void*>(baseBuffer.get()); - size_t size = baseSize; - int* fds = baseFds.get(); - size_t numFds = baseNumFds; - if (l.flatten(buffer, size, fds, numFds) != NO_ERROR) { - return false; - } - - void const* constBuffer = static_cast<void const*>(baseBuffer.get()); - size = baseSize; - int const* constFds = static_cast<int const*>(baseFds.get()); - numFds = baseNumFds; - if (unflatten(t, nh, constBuffer, size, constFds, numFds) != NO_ERROR) { - return false; - } - - return true; -} /** * \brief Convert `HGraphicBufferProducer::QueueBufferInput` to diff --git a/libs/gui/bufferqueue/1.0/H2BProducerListener.cpp b/libs/gui/bufferqueue/1.0/H2BProducerListener.cpp index 2712f42c89..598c8dea9b 100644 --- a/libs/gui/bufferqueue/1.0/H2BProducerListener.cpp +++ b/libs/gui/bufferqueue/1.0/H2BProducerListener.cpp @@ -32,7 +32,11 @@ namespace utils { using ::android::hardware::Return; H2BProducerListener::H2BProducerListener(sp<HProducerListener> const& base) +#ifndef NO_BINDER : CBase{base} { +#else + : mBase(base) { +#endif } void H2BProducerListener::onBufferReleased() { diff --git a/libs/gui/bufferqueue/1.0/WProducerListener.cpp b/libs/gui/bufferqueue/1.0/WProducerListener.cpp index 78dc4e8b18..56b64b9ddd 100644 --- a/libs/gui/bufferqueue/1.0/WProducerListener.cpp +++ b/libs/gui/bufferqueue/1.0/WProducerListener.cpp @@ -46,5 +46,7 @@ void LWProducerListener::onBufferReleased() { bool LWProducerListener::needsReleaseNotify() { return static_cast<bool>(mBase->needsReleaseNotify()); } +void LWProducerListener::onBuffersDiscarded(const std::vector<int32_t>& /*slots*/) { +} } // namespace android diff --git a/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp b/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp index e891ec581e..c76d771262 100644 --- a/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp +++ b/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp @@ -249,6 +249,24 @@ Return<void> B2HGraphicBufferProducer::query(int32_t what, query_cb _hidl_cb) { return {}; } +struct Obituary : public hardware::hidl_death_recipient { + wp<B2HGraphicBufferProducer> producer; + sp<HProducerListener> listener; + HConnectionType apiType; + Obituary(const wp<B2HGraphicBufferProducer>& p, + const sp<HProducerListener>& l, + HConnectionType t) + : producer(p), listener(l), apiType(t) {} + + void serviceDied(uint64_t /* cookie */, + const wp<::android::hidl::base::V1_0::IBase>& /* who */) override { + sp<B2HGraphicBufferProducer> dr = producer.promote(); + if (dr != nullptr) { + (void)dr->disconnect(apiType); + } + } +}; + Return<void> B2HGraphicBufferProducer::connect( sp<HProducerListener> const& hListener, HConnectionType hConnectionType, @@ -270,6 +288,12 @@ Return<void> B2HGraphicBufferProducer::connect( &bOutput), &hStatus) && b2h(bOutput, &hOutput); +#ifdef NO_BINDER + if (converted && hListener != nullptr) { + mObituary = new Obituary(this, hListener, hConnectionType); + hListener->linkToDeath(mObituary, 0); + } +#endif // NO_BINDER _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR, hOutput); return {}; } @@ -282,6 +306,12 @@ Return<HStatus> B2HGraphicBufferProducer::disconnect( } HStatus hStatus{}; bool converted = b2h(mBase->disconnect(bConnectionType), &hStatus); +#ifdef NO_BINDER + if (mObituary != nullptr) { + mObituary->listener->unlinkToDeath(mObituary); + mObituary.clear(); + } +#endif // NO_BINDER return {converted ? hStatus : HStatus::UNKNOWN_ERROR}; } diff --git a/libs/gui/bufferqueue/2.0/H2BProducerListener.cpp b/libs/gui/bufferqueue/2.0/H2BProducerListener.cpp index b81a357d63..b2bd1172d6 100644 --- a/libs/gui/bufferqueue/2.0/H2BProducerListener.cpp +++ b/libs/gui/bufferqueue/2.0/H2BProducerListener.cpp @@ -32,7 +32,11 @@ namespace utils { using ::android::hardware::Return; H2BProducerListener::H2BProducerListener(sp<HProducerListener> const& base) +#ifndef NO_BINDER : CBase{base} { +#else + : mBase(base) { +#endif } void H2BProducerListener::onBufferReleased() { @@ -48,6 +52,9 @@ bool H2BProducerListener::needsReleaseNotify() { return static_cast<bool>(mBase); } +void H2BProducerListener::onBuffersDiscarded(const std::vector<int32_t>& /*slots*/) { +} + } // namespace utils } // namespace V2_0 } // namespace bufferqueue diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h new file mode 100644 index 0000000000..2320771a38 --- /dev/null +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2019 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_GUI_BLAST_BUFFER_QUEUE_H +#define ANDROID_GUI_BLAST_BUFFER_QUEUE_H + +#include <gui/IGraphicBufferProducer.h> +#include <gui/BufferItemConsumer.h> +#include <gui/BufferItem.h> +#include <gui/SurfaceComposerClient.h> + +#include <utils/Condition.h> +#include <utils/Mutex.h> +#include <utils/RefBase.h> + +#include <system/window.h> +#include <thread> + +namespace android { + +class BufferItemConsumer; + +class BLASTBufferItemConsumer : public BufferItemConsumer { +public: + BLASTBufferItemConsumer(const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage, + int bufferCount, bool controlledByApp) + : BufferItemConsumer(consumer, consumerUsage, bufferCount, controlledByApp), + mCurrentlyConnected(false), + mPreviouslyConnected(false) {} + + void onDisconnect() override; + void addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps, + FrameEventHistoryDelta* outDelta) override + REQUIRES(mFrameEventHistoryMutex); + void updateFrameTimestamps(uint64_t frameNumber, nsecs_t refreshStartTime, + const sp<Fence>& gpuCompositionDoneFence, + const sp<Fence>& presentFence, const sp<Fence>& prevReleaseFence, + CompositorTiming compositorTiming, nsecs_t latchTime, + nsecs_t dequeueReadyTime) REQUIRES(mFrameEventHistoryMutex); + void getConnectionEvents(uint64_t frameNumber, bool* needsDisconnect); + +private: + uint64_t mCurrentFrameNumber = 0; + + Mutex mFrameEventHistoryMutex; + ConsumerFrameEventHistory mFrameEventHistory GUARDED_BY(mFrameEventHistoryMutex); + std::queue<uint64_t> mDisconnectEvents GUARDED_BY(mFrameEventHistoryMutex); + bool mCurrentlyConnected GUARDED_BY(mFrameEventHistoryMutex); + bool mPreviouslyConnected GUARDED_BY(mFrameEventHistoryMutex); +}; + +class BLASTBufferQueue + : public ConsumerBase::FrameAvailableListener, public BufferItemConsumer::BufferFreedListener +{ +public: + BLASTBufferQueue(const sp<SurfaceControl>& surface, int width, int height, + bool enableTripleBuffering = true); + + sp<IGraphicBufferProducer> getIGraphicBufferProducer() const { + return mProducer; + } + + void onBufferFreed(const wp<GraphicBuffer>&/* graphicBuffer*/) override { /* TODO */ } + void onFrameReplaced(const BufferItem& item) override {onFrameAvailable(item);} + void onFrameAvailable(const BufferItem& item) override; + + void transactionCallback(nsecs_t latchTime, const sp<Fence>& presentFence, + const std::vector<SurfaceControlStats>& stats); + void setNextTransaction(SurfaceComposerClient::Transaction *t); + + void update(const sp<SurfaceControl>& surface, int width, int height); + + virtual ~BLASTBufferQueue() = default; + +private: + friend class BLASTBufferQueueHelper; + + // can't be copied + BLASTBufferQueue& operator = (const BLASTBufferQueue& rhs); + BLASTBufferQueue(const BLASTBufferQueue& rhs); + + void processNextBufferLocked(bool useNextTransaction) REQUIRES(mMutex); + Rect computeCrop(const BufferItem& item); + + sp<SurfaceControl> mSurfaceControl; + + std::mutex mMutex; + std::condition_variable mCallbackCV; + + // BufferQueue internally allows 1 more than + // the max to be acquired + static const int MAX_ACQUIRED_BUFFERS = 1; + + int32_t mNumFrameAvailable GUARDED_BY(mMutex); + int32_t mNumAcquired GUARDED_BY(mMutex); + + struct PendingReleaseItem { + BufferItem item; + sp<Fence> releaseFence; + }; + + std::queue<const BufferItem> mSubmitted GUARDED_BY(mMutex); + PendingReleaseItem mPendingReleaseItem GUARDED_BY(mMutex); + + int mWidth GUARDED_BY(mMutex); + int mHeight GUARDED_BY(mMutex); + + uint32_t mTransformHint GUARDED_BY(mMutex); + + sp<IGraphicBufferConsumer> mConsumer; + sp<IGraphicBufferProducer> mProducer; + sp<BLASTBufferItemConsumer> mBufferItemConsumer; + + SurfaceComposerClient::Transaction* mNextTransaction GUARDED_BY(mMutex); +}; + +} // namespace android + +#endif // ANDROID_GUI_SURFACE_H diff --git a/libs/gui/include/gui/BufferQueue.h b/libs/gui/include/gui/BufferQueue.h index da952744f3..91f80d2f17 100644 --- a/libs/gui/include/gui/BufferQueue.h +++ b/libs/gui/include/gui/BufferQueue.h @@ -63,6 +63,9 @@ public: void onFrameReplaced(const BufferItem& item) override; void onBuffersReleased() override; void onSidebandStreamChanged() override; + void onFrameDequeued(const uint64_t bufferId) override; + void onFrameCancelled(const uint64_t bufferId) override; + void onFrameDetached(const uint64_t bufferID) override; void addAndGetFrameTimestamps( const NewFrameEventsEntry* newTimestamps, FrameEventHistoryDelta* outDelta) override; diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h index 17617bce13..557c28b1b7 100644 --- a/libs/gui/include/gui/BufferQueueCore.h +++ b/libs/gui/include/gui/BufferQueueCore.h @@ -34,12 +34,6 @@ #include <mutex> #include <condition_variable> -#define BQ_LOGV(x, ...) ALOGV("[%s] " x, mConsumerName.string(), ##__VA_ARGS__) -#define BQ_LOGD(x, ...) ALOGD("[%s] " x, mConsumerName.string(), ##__VA_ARGS__) -#define BQ_LOGI(x, ...) ALOGI("[%s] " x, mConsumerName.string(), ##__VA_ARGS__) -#define BQ_LOGW(x, ...) ALOGW("[%s] " x, mConsumerName.string(), ##__VA_ARGS__) -#define BQ_LOGE(x, ...) ALOGE("[%s] " x, mConsumerName.string(), ##__VA_ARGS__) - #define ATRACE_BUFFER_INDEX(index) \ do { \ if (ATRACE_ENABLED()) { \ @@ -352,6 +346,14 @@ private: const uint64_t mUniqueId; + // When buffer size is driven by the consumer and mTransformHint specifies + // a 90 or 270 degree rotation, this indicates whether the width and height + // used by dequeueBuffer will be additionally swapped. + bool mAutoPrerotation; + + // mTransformHintInUse is to cache the mTransformHint used by the producer. + uint32_t mTransformHintInUse; + }; // class BufferQueueCore } // namespace android diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h index d2a47a6aa8..a7f7d1defa 100644 --- a/libs/gui/include/gui/BufferQueueProducer.h +++ b/libs/gui/include/gui/BufferQueueProducer.h @@ -22,10 +22,15 @@ namespace android { +class IBinder; struct BufferSlot; +#ifndef NO_BINDER class BufferQueueProducer : public BnGraphicBufferProducer, private IBinder::DeathRecipient { +#else +class BufferQueueProducer : public BnGraphicBufferProducer { +#endif public: friend class BufferQueue; // Needed to access binderDied @@ -190,6 +195,9 @@ public: // See IGraphicBufferProducer::getConsumerUsage virtual status_t getConsumerUsage(uint64_t* outUsage) const override; + // See IGraphicBufferProducer::setAutoPrerotation + virtual status_t setAutoPrerotation(bool autoPrerotation); + private: // This is required by the IBinder::DeathRecipient interface virtual void binderDied(const wp<IBinder>& who); diff --git a/libs/gui/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h index 366ced380b..8ff0cd0f6e 100644 --- a/libs/gui/include/gui/ConsumerBase.h +++ b/libs/gui/include/gui/ConsumerBase.h @@ -45,6 +45,9 @@ public: // See IConsumerListener::onFrame{Available,Replaced} virtual void onFrameAvailable(const BufferItem& item) = 0; virtual void onFrameReplaced(const BufferItem& /* item */) {} + virtual void onFrameDequeued(const uint64_t){}; + virtual void onFrameCancelled(const uint64_t){}; + virtual void onFrameDetached(const uint64_t){}; }; ~ConsumerBase() override; @@ -141,6 +144,9 @@ protected: // classes if they want the notification. virtual void onFrameAvailable(const BufferItem& item) override; virtual void onFrameReplaced(const BufferItem& item) override; + virtual void onFrameDequeued(const uint64_t bufferId) override; + virtual void onFrameCancelled(const uint64_t bufferId) override; + virtual void onFrameDetached(const uint64_t bufferId) override; virtual void onBuffersReleased() override; virtual void onSidebandStreamChanged() override; diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h new file mode 100644 index 0000000000..f210c34196 --- /dev/null +++ b/libs/gui/include/gui/DisplayEventDispatcher.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2015 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <gui/DisplayEventReceiver.h> +#include <utils/Log.h> +#include <utils/Looper.h> + +namespace android { + +class DisplayEventDispatcher : public LooperCallback { +public: + explicit DisplayEventDispatcher( + const sp<Looper>& looper, + ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp, + ISurfaceComposer::ConfigChanged configChanged = + ISurfaceComposer::eConfigChangedSuppress); + + status_t initialize(); + void dispose(); + status_t scheduleVsync(); + void requestLatestConfig(); + int getFd() const; + virtual int handleEvent(int receiveFd, int events, void* data); + +protected: + virtual ~DisplayEventDispatcher() = default; + +private: + sp<Looper> mLooper; + DisplayEventReceiver mReceiver; + bool mWaitingForVsync; + + virtual void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) = 0; + virtual void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, + bool connected) = 0; + virtual void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId, + int32_t configId, nsecs_t vsyncPeriod) = 0; + + bool processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId, + uint32_t* outCount); +}; +} // namespace android diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h index a558cf9e18..8d49184caf 100644 --- a/libs/gui/include/gui/DisplayEventReceiver.h +++ b/libs/gui/include/gui/DisplayEventReceiver.h @@ -65,6 +65,7 @@ public: struct VSync { uint32_t count; + nsecs_t expectedVSyncTimestamp; }; struct Hotplug { @@ -73,6 +74,7 @@ public: struct Config { int32_t configId; + nsecs_t vsyncPeriod; }; Header header; @@ -144,6 +146,12 @@ public: */ status_t requestNextVsync(); + /* + * requestLatestConfig() force-requests the current config for the primary + * display. + */ + status_t requestLatestConfig(); + private: sp<IDisplayEventConnection> mEventConnection; std::unique_ptr<gui::BitTube> mDataChannel; diff --git a/libs/gui/include/gui/FrameTimestamps.h b/libs/gui/include/gui/FrameTimestamps.h index 4670edda99..0750080e1c 100644 --- a/libs/gui/include/gui/FrameTimestamps.h +++ b/libs/gui/include/gui/FrameTimestamps.h @@ -175,7 +175,6 @@ struct NewFrameEventsEntry { std::shared_ptr<FenceTime> acquireFence{FenceTime::NO_FENCE}; }; - // Used by the consumer to keep track of which fields it already sent to // the producer. class FrameEventDirtyFields { @@ -209,6 +208,7 @@ public: ~ConsumerFrameEventHistory() override; void onDisconnect(); + void setProducerWantsEvents(); void initializeCompositorTiming(const CompositorTiming& compositorTiming); diff --git a/libs/gui/include/gui/GLConsumer.h b/libs/gui/include/gui/GLConsumer.h index ddd868d7d1..2f538ffb86 100644 --- a/libs/gui/include/gui/GLConsumer.h +++ b/libs/gui/include/gui/GLConsumer.h @@ -499,7 +499,7 @@ private: // protects static initialization static Mutex sStaticInitLock; - // mReleasedTexImageBuffer is a dummy buffer used when in single buffer + // mReleasedTexImageBuffer is a buffer placeholder used when in single buffer // mode and releaseTexImage() has been called static sp<GraphicBuffer> sReleasedTexImageBuffer; sp<EglImage> mReleasedTexImage; diff --git a/libs/gui/include/gui/IConsumerListener.h b/libs/gui/include/gui/IConsumerListener.h index c0828820e3..0ab2399eb2 100644 --- a/libs/gui/include/gui/IConsumerListener.h +++ b/libs/gui/include/gui/IConsumerListener.h @@ -43,6 +43,17 @@ public: // onDisconnect is called when a producer disconnects from the BufferQueue. virtual void onDisconnect() {} /* Asynchronous */ + // onFrameDequeued is called when a call to the BufferQueueProducer::dequeueBuffer successfully + // returns a slot from the BufferQueue. + virtual void onFrameDequeued(const uint64_t) {} + + // onFrameCancelled is called when the client calls cancelBuffer, thereby releasing the slot + // back to the BufferQueue. + virtual void onFrameCancelled(const uint64_t) {} + + // onFrameDetached is called after a successful detachBuffer() call while in asynchronous mode. + virtual void onFrameDetached(const uint64_t) {} + // onFrameAvailable is called from queueBuffer each time an additional frame becomes available // for consumption. This means that frames that are queued while in asynchronous mode only // trigger the callback if no previous frames are pending. Frames queued while in synchronous @@ -81,6 +92,7 @@ public: FrameEventHistoryDelta* /*outDelta*/) {} }; +#ifndef NO_BINDER class IConsumerListener : public ConsumerListener, public IInterface { public: DECLARE_META_INTERFACE(ConsumerListener) @@ -94,4 +106,11 @@ public: uint32_t flags = 0) override; }; +#else +class IConsumerListener : public ConsumerListener { +}; +class BnConsumerListener : public IConsumerListener { +}; +#endif + } // namespace android diff --git a/libs/gui/include/gui/IDisplayEventConnection.h b/libs/gui/include/gui/IDisplayEventConnection.h index d783f74d7c..674aafd81c 100644 --- a/libs/gui/include/gui/IDisplayEventConnection.h +++ b/libs/gui/include/gui/IDisplayEventConnection.h @@ -18,7 +18,7 @@ #include <binder/IInterface.h> #include <binder/SafeInterface.h> - +#include <gui/ISurfaceComposer.h> #include <utils/Errors.h> #include <cstdint> @@ -51,6 +51,11 @@ public: * requestNextVsync() schedules the next vsync event. It has no effect if the vsync rate is > 0. */ virtual void requestNextVsync() = 0; // Asynchronous + + /* + * requestLatestConfig() requests the config for the primary display. + */ + virtual void requestLatestConfig() = 0; // Asynchronous }; class BnDisplayEventConnection : public SafeBnInterface<IDisplayEventConnection> { diff --git a/libs/gui/include/gui/IGraphicBufferConsumer.h b/libs/gui/include/gui/IGraphicBufferConsumer.h index 9fb7580912..0b92e7df62 100644 --- a/libs/gui/include/gui/IGraphicBufferConsumer.h +++ b/libs/gui/include/gui/IGraphicBufferConsumer.h @@ -35,10 +35,14 @@ class Fence; class GraphicBuffer; class IConsumerListener; class NativeHandle; - +#ifndef NO_BINDER class IGraphicBufferConsumer : public IInterface { public: DECLARE_META_INTERFACE(GraphicBufferConsumer) +#else +class IGraphicBufferConsumer : public RefBase { +public: +#endif enum { // Returned by releaseBuffer, after which the consumer must free any references to the @@ -282,6 +286,7 @@ public: } }; +#ifndef NO_BINDER class BnGraphicBufferConsumer : public SafeBnInterface<IGraphicBufferConsumer> { public: BnGraphicBufferConsumer() @@ -290,5 +295,9 @@ public: status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) override; }; +#else +class BnGraphicBufferConsumer : public IGraphicBufferConsumer { +}; +#endif } // namespace android diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h index 3dde8c8c80..45e0a134ba 100644 --- a/libs/gui/include/gui/IGraphicBufferProducer.h +++ b/libs/gui/include/gui/IGraphicBufferProducer.h @@ -45,6 +45,13 @@ class IProducerListener; class NativeHandle; class Surface; +using HGraphicBufferProducerV1_0 = + ::android::hardware::graphics::bufferqueue::V1_0:: + IGraphicBufferProducer; +using HGraphicBufferProducerV2_0 = + ::android::hardware::graphics::bufferqueue::V2_0:: + IGraphicBufferProducer; + /* * This class defines the Binder IPC interface for the producer side of * a queue of graphics buffers. It's used to send graphics data from one @@ -59,20 +66,15 @@ class Surface; * * This class was previously called ISurfaceTexture. */ -class IGraphicBufferProducer : public IInterface -{ -public: - using HGraphicBufferProducerV1_0 = - ::android::hardware::graphics::bufferqueue::V1_0:: - IGraphicBufferProducer; - using HGraphicBufferProducerV2_0 = - ::android::hardware::graphics::bufferqueue::V2_0:: - IGraphicBufferProducer; - +#ifndef NO_BINDER +class IGraphicBufferProducer : public IInterface { DECLARE_HYBRID_META_INTERFACE(GraphicBufferProducer, HGraphicBufferProducerV1_0, HGraphicBufferProducerV2_0) - +#else +class IGraphicBufferProducer : public RefBase { +#endif +public: enum { // A flag returned by dequeueBuffer when the client needs to call // requestBuffer immediately thereafter. @@ -286,36 +288,6 @@ public: virtual status_t attachBuffer(int* outSlot, const sp<GraphicBuffer>& buffer) = 0; - // queueBuffer indicates that the client has finished filling in the - // contents of the buffer associated with slot and transfers ownership of - // that slot back to the server. - // - // It is not valid to call queueBuffer on a slot that is not owned - // by the client or one for which a buffer associated via requestBuffer - // (an attempt to do so will fail with a return value of BAD_VALUE). - // - // In addition, the input must be described by the client (as documented - // below). Any other properties (zero point, etc) - // are client-dependent, and should be documented by the client. - // - // The slot must be in the range of [0, NUM_BUFFER_SLOTS). - // - // Upon success, the output will be filled with meaningful values - // (refer to the documentation below). - // - // Return of a value other than NO_ERROR means an error has occurred: - // * NO_INIT - the buffer queue has been abandoned or the producer is not - // connected. - // * BAD_VALUE - one of the below conditions occurred: - // * fence was NULL - // * scaling mode was unknown - // * both in async mode and buffer count was less than the - // max numbers of buffers that can be allocated at once - // * slot index was out of range (see above). - // * the slot was not in the dequeued state - // * the slot was enqueued without requesting a buffer - // * crop rect is out of bounds of the buffer dimensions - struct QueueBufferInput : public Flattenable<QueueBufferInput> { friend class Flattenable<QueueBufferInput>; explicit inline QueueBufferInput(const Parcel& parcel); @@ -412,8 +384,38 @@ public: uint64_t nextFrameNumber{0}; FrameEventHistoryDelta frameTimestamps; bool bufferReplaced{false}; + int maxBufferCount{0}; }; + // queueBuffer indicates that the client has finished filling in the + // contents of the buffer associated with slot and transfers ownership of + // that slot back to the server. + // + // It is not valid to call queueBuffer on a slot that is not owned + // by the client or one for which a buffer associated via requestBuffer + // (an attempt to do so will fail with a return value of BAD_VALUE). + // + // In addition, the input must be described by the client (as documented + // below). Any other properties (zero point, etc) + // are client-dependent, and should be documented by the client. + // + // The slot must be in the range of [0, NUM_BUFFER_SLOTS). + // + // Upon success, the output will be filled with meaningful values + // (refer to the documentation below). + // + // Return of a value other than NO_ERROR means an error has occurred: + // * NO_INIT - the buffer queue has been abandoned or the producer is not + // connected. + // * BAD_VALUE - one of the below conditions occurred: + // * fence was NULL + // * scaling mode was unknown + // * both in async mode and buffer count was less than the + // max numbers of buffers that can be allocated at once + // * slot index was out of range (see above). + // * the slot was not in the dequeued state + // * the slot was enqueued without requesting a buffer + // * crop rect is out of bounds of the buffer dimensions virtual status_t queueBuffer(int slot, const QueueBufferInput& input, QueueBufferOutput* output) = 0; @@ -456,7 +458,7 @@ public: // the producer wants to be notified when the consumer releases a buffer // back to the BufferQueue. It is also used to detect the death of the // producer. If only the latter functionality is desired, there is a - // DummyProducerListener class in IProducerListener.h that can be used. + // StubProducerListener class in IProducerListener.h that can be used. // // The api should be one of the NATIVE_WINDOW_API_* values in <window.h> // @@ -629,6 +631,15 @@ public: // NATIVE_WINDOW_CONSUMER_USAGE_BITS attribute. virtual status_t getConsumerUsage(uint64_t* outUsage) const = 0; + // Enable/disable the auto prerotation at buffer allocation when the buffer + // size is driven by the consumer. + // + // When buffer size is driven by the consumer and the transform hint + // specifies a 90 or 270 degree rotation, if auto prerotation is enabled, + // the width and height used for dequeueBuffer will be additionally swapped. + virtual status_t setAutoPrerotation(bool autoPrerotation); + +#ifndef NO_BINDER // Static method exports any IGraphicBufferProducer object to a parcel. It // handles null producer as well. static status_t exportToParcel(const sp<IGraphicBufferProducer>& producer, @@ -646,10 +657,11 @@ protected: // it writes a strong binder object; for BufferHub, it writes a // ProducerQueueParcelable object. virtual status_t exportToParcel(Parcel* parcel); +#endif }; // ---------------------------------------------------------------------------- - +#ifndef NO_BINDER class BnGraphicBufferProducer : public BnInterface<IGraphicBufferProducer> { public: @@ -658,6 +670,10 @@ public: Parcel* reply, uint32_t flags = 0); }; +#else +class BnGraphicBufferProducer : public IGraphicBufferProducer { +}; +#endif // ---------------------------------------------------------------------------- }; // namespace android diff --git a/libs/gui/include/gui/IProducerListener.h b/libs/gui/include/gui/IProducerListener.h index 32a3690ff2..f7ffbb99ea 100644 --- a/libs/gui/include/gui/IProducerListener.h +++ b/libs/gui/include/gui/IProducerListener.h @@ -51,6 +51,7 @@ public: virtual void onBuffersDiscarded(const std::vector<int32_t>& slots) = 0; // Asynchronous }; +#ifndef NO_BINDER class IProducerListener : public ProducerListener, public IInterface { public: @@ -73,10 +74,15 @@ public: virtual void onBuffersDiscarded(const std::vector<int32_t>& slots); }; -class DummyProducerListener : public BnProducerListener -{ +#else +class IProducerListener : public ProducerListener { +}; +class BnProducerListener : public IProducerListener { +}; +#endif +class StubProducerListener : public BnProducerListener { public: - virtual ~DummyProducerListener(); + virtual ~StubProducerListener(); virtual void onBufferReleased() {} virtual bool needsReleaseNotify() { return false; } }; diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index c84910b6ec..8d3160a815 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_GUI_ISURFACE_COMPOSER_H -#define ANDROID_GUI_ISURFACE_COMPOSER_H +#pragma once #include <stdint.h> #include <sys/types.h> @@ -25,12 +24,16 @@ #include <gui/ITransactionCompletedListener.h> +#include <math/vec4.h> + #include <ui/ConfigStoreTypes.h> #include <ui/DisplayedFrameStats.h> #include <ui/FrameStats.h> #include <ui/GraphicBuffer.h> #include <ui/GraphicTypes.h> +#include <ui/PhysicalDisplayId.h> #include <ui/PixelFormat.h> +#include <ui/Rotation.h> #include <utils/Errors.h> #include <utils/RefBase.h> @@ -42,13 +45,13 @@ #include <vector> namespace android { -// ---------------------------------------------------------------------------- struct client_cache_t; struct ComposerState; -struct DisplayState; +struct DisplayConfig; struct DisplayInfo; struct DisplayStatInfo; +struct DisplayState; struct InputWindowCommands; class LayerDebugInfo; class HdrCapabilities; @@ -59,6 +62,12 @@ class IRegionSamplingListener; class Rect; enum class FrameEvent; +namespace ui { + +struct DisplayState; + +} // namespace ui + /* * This class defines the Binder IPC interface for accessing various * SurfaceFlinger features. @@ -67,22 +76,25 @@ class ISurfaceComposer: public IInterface { public: DECLARE_META_INTERFACE(SurfaceComposer) + static constexpr size_t MAX_LAYERS = 4096; + // flags for setTransactionState() enum { eSynchronous = 0x01, - eAnimation = 0x02, - - // Indicates that this transaction will likely result in a lot of layers being composed, and - // thus, SurfaceFlinger should wake-up earlier to avoid missing frame deadlines. In this - // case SurfaceFlinger will wake up at (sf vsync offset - debug.sf.early_phase_offset_ns) - eEarlyWakeup = 0x04 - }; - - enum Rotation { - eRotateNone = 0, - eRotate90 = 1, - eRotate180 = 2, - eRotate270 = 3 + eAnimation = 0x02, + + // DEPRECATED - use eExplicitEarlyWakeup[Start|End] + eEarlyWakeup = 0x04, + + // Explicit indication that this transaction and others to follow will likely result in a + // lot of layers being composed, and thus, SurfaceFlinger should wake-up earlier to avoid + // missing frame deadlines. In this case SurfaceFlinger will wake up at + // (sf vsync offset - debug.sf.early_phase_offset_ns). SurfaceFlinger will continue to be + // in the early configuration until it receives eExplicitEarlyWakeupEnd. These flags are + // expected to be used by WindowManager only and are guarded by + // android.permission.ACCESS_SURFACE_FLINGER + eExplicitEarlyWakeupStart = 0x08, + eExplicitEarlyWakeupEnd = 0x10, }; enum VsyncSource { @@ -140,7 +152,7 @@ public: const sp<IBinder>& applyToken, const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime, - const client_cache_t& uncacheBuffer, + const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks) = 0; /* signal that we're done booting. @@ -164,10 +176,6 @@ public: */ virtual void setPowerMode(const sp<IBinder>& display, int mode) = 0; - /* returns information for each configuration of the given display - * intended to be used to get information about built-in displays */ - virtual status_t getDisplayConfigs(const sp<IBinder>& display, - Vector<DisplayInfo>* configs) = 0; /* returns display statistics for a given display * intended to be used by the media framework to properly schedule @@ -175,13 +183,26 @@ public: virtual status_t getDisplayStats(const sp<IBinder>& display, DisplayStatInfo* stats) = 0; - /* indicates which of the configurations returned by getDisplayInfo is - * currently active */ - virtual int getActiveConfig(const sp<IBinder>& display) = 0; + /** + * Get transactional state of given display. + */ + virtual status_t getDisplayState(const sp<IBinder>& display, ui::DisplayState*) = 0; - /* specifies which configuration (of those returned by getDisplayInfo) - * should be used */ - virtual status_t setActiveConfig(const sp<IBinder>& display, int id) = 0; + /** + * Get immutable information about given physical display. + */ + virtual status_t getDisplayInfo(const sp<IBinder>& display, DisplayInfo*) = 0; + + /** + * Get configurations supported by given physical display. + */ + virtual status_t getDisplayConfigs(const sp<IBinder>& display, Vector<DisplayConfig>*) = 0; + + /** + * Get the index into configurations returned by getDisplayConfigs, + * corresponding to the active configuration. + */ + virtual int getActiveConfig(const sp<IBinder>& display) = 0; virtual status_t getDisplayColorModes(const sp<IBinder>& display, Vector<ui::ColorMode>* outColorModes) = 0; @@ -192,6 +213,37 @@ public: ui::ColorMode colorMode) = 0; /** + * Returns true if the connected display reports support for HDMI 2.1 Auto + * Low Latency Mode. + * For more information, see the HDMI 2.1 specification. + */ + virtual status_t getAutoLowLatencyModeSupport(const sp<IBinder>& display, + bool* outSupport) const = 0; + + /** + * Switches Auto Low Latency Mode on/off on the connected display, if it is + * available. This should only be called if #getAutoLowLatencyMode returns + * true. + * For more information, see the HDMI 2.1 specification. + */ + virtual void setAutoLowLatencyMode(const sp<IBinder>& display, bool on) = 0; + + /** + * Returns true if the connected display reports support for Game Content Type. + * For more information, see the HDMI 1.4 specification. + */ + virtual status_t getGameContentTypeSupport(const sp<IBinder>& display, + bool* outSupport) const = 0; + + /** + * This will start sending infoframes to the connected display with + * ContentType=Game (if on=true). This will switch the disply to Game mode. + * This should only be called if #getGameContentTypeSupport returns true. + * For more information, see the HDMI 1.4 specification. + */ + virtual void setGameContentType(const sp<IBinder>& display, bool on) = 0; + + /** * Capture the specified screen. This requires READ_FRAME_BUFFER * permission. This function will fail if there is a secure window on * screen. @@ -215,10 +267,10 @@ public: * it) around its center. */ virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer, - bool& outCapturedSecureLayers, const ui::Dataspace reqDataspace, - const ui::PixelFormat reqPixelFormat, Rect sourceCrop, + bool& outCapturedSecureLayers, ui::Dataspace reqDataspace, + ui::PixelFormat reqPixelFormat, const Rect& sourceCrop, uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform, - Rotation rotation = eRotateNone, + ui::Rotation rotation = ui::ROTATION_0, bool captureSecureLayers = false) = 0; /** * Capture the specified screen. This requires READ_FRAME_BUFFER @@ -242,8 +294,9 @@ public: * it) around its center. */ virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - bool useIdentityTransform, Rotation rotation = eRotateNone) { + const Rect& sourceCrop, uint32_t reqWidth, uint32_t reqHeight, + bool useIdentityTransform, + ui::Rotation rotation = ui::ROTATION_0) { bool outIgnored; return captureScreen(display, outBuffer, outIgnored, ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888, sourceCrop, reqWidth, reqHeight, @@ -267,8 +320,7 @@ public: */ virtual status_t captureLayers( const sp<IBinder>& layerHandleBinder, sp<GraphicBuffer>* outBuffer, - const ui::Dataspace reqDataspace, const ui::PixelFormat reqPixelFormat, - const Rect& sourceCrop, + ui::Dataspace reqDataspace, ui::PixelFormat reqPixelFormat, const Rect& sourceCrop, const std::unordered_set<sp<IBinder>, SpHash<IBinder>>& excludeHandles, float frameScale = 1.0, bool childrenOnly = false) = 0; @@ -310,7 +362,7 @@ public: * * Requires the ACCESS_SURFACE_FLINGER permission. */ - virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const = 0; + virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) = 0; virtual status_t getColorManagement(bool* outGetColorManagement) const = 0; @@ -339,7 +391,7 @@ public: */ virtual status_t setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable, uint8_t componentMask, - uint64_t maxFrames) const = 0; + uint64_t maxFrames) = 0; /* Returns statistics on the color profile of the last frame displayed for a given display * @@ -382,21 +434,36 @@ public: */ virtual status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) = 0; - /* - * Sets the allowed display configurations to be used. - * The allowedConfigs in a vector of indexes corresponding to the configurations - * returned from getDisplayConfigs(). - */ - virtual status_t setAllowedDisplayConfigs(const sp<IBinder>& displayToken, - const std::vector<int32_t>& allowedConfigs) = 0; - - /* - * Returns the allowed display configurations currently set. - * The allowedConfigs in a vector of indexes corresponding to the configurations + /* Sets the refresh rate boundaries for the display. + * + * The primary refresh rate range represents display manager's general guidance on the display + * configs we'll consider when switching refresh rates. Unless we get an explicit signal from an + * app, we should stay within this range. + * + * The app request refresh rate range allows us to consider more display configs when switching + * refresh rates. Although we should generally stay within the primary range, specific + * considerations, such as layer frame rate settings specified via the setFrameRate() api, may + * cause us to go outside the primary range. We never go outside the app request range. The app + * request range will be greater than or equal to the primary refresh rate range, never smaller. + * + * defaultConfig is used to narrow the list of display configs SurfaceFlinger will consider + * switching between. Only configs with a config group and resolution matching defaultConfig + * will be considered for switching. The defaultConfig index corresponds to the list of configs * returned from getDisplayConfigs(). */ - virtual status_t getAllowedDisplayConfigs(const sp<IBinder>& displayToken, - std::vector<int32_t>* outAllowedConfigs) = 0; + virtual status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken, + int32_t defaultConfig, + float primaryRefreshRateMin, + float primaryRefreshRateMax, + float appRequestRefreshRateMin, + float appRequestRefreshRateMax) = 0; + + virtual status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken, + int32_t* outDefaultConfig, + float* outPrimaryRefreshRateMin, + float* outPrimaryRefreshRateMax, + float* outAppRequestRefreshRateMin, + float* outAppRequestRefreshRateMax) = 0; /* * Gets whether brightness operations are supported on a display. * @@ -426,8 +493,7 @@ public: * BAD_VALUE if the brightness is invalid, or * INVALID_OPERATION if brightness operations are not supported. */ - virtual status_t setDisplayBrightness(const sp<IBinder>& displayToken, - float brightness) const = 0; + virtual status_t setDisplayBrightness(const sp<IBinder>& displayToken, float brightness) = 0; /* * Sends a power hint to the composer. This function is asynchronous. @@ -438,6 +504,42 @@ public: * Returns NO_ERROR upon success. */ virtual status_t notifyPowerHint(int32_t hintId) = 0; + + /* + * Sets the global configuration for all the shadows drawn by SurfaceFlinger. Shadow follows + * material design guidelines. + * + * ambientColor + * Color to the ambient shadow. The alpha is premultiplied. + * + * spotColor + * Color to the spot shadow. The alpha is premultiplied. The position of the spot shadow + * depends on the light position. + * + * lightPosY/lightPosZ + * Position of the light used to cast the spot shadow. The X value is always the display + * width / 2. + * + * lightRadius + * Radius of the light casting the shadow. + */ + virtual status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, + float lightPosY, float lightPosZ, + float lightRadius) = 0; + + /* + * Sets the intended frame rate for a surface. See ANativeWindow_setFrameRate() for more info. + */ + virtual status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate, + int8_t compatibility) = 0; + + /* + * Acquire a frame rate flexibility token from SurfaceFlinger. While this token is acquired, + * surface flinger will freely switch between frame rates in any way it sees fit, regardless of + * the current restrictions applied by DisplayManager. This is useful to get consistent behavior + * for tests. Release the token by releasing the returned IBinder reference. + */ + virtual status_t acquireFrameRateFlexibilityToken(sp<IBinder>* outToken) = 0; }; // ---------------------------------------------------------------------------- @@ -449,7 +551,7 @@ public: // Java by ActivityManagerService. BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION, CREATE_CONNECTION, - CREATE_GRAPHIC_BUFFER_ALLOC_UNUSED, // unused, fails permissions check + GET_DISPLAY_INFO, CREATE_DISPLAY_EVENT_CONNECTION, CREATE_DISPLAY, DESTROY_DISPLAY, @@ -459,8 +561,7 @@ public: GET_SUPPORTED_FRAME_TIMESTAMPS, GET_DISPLAY_CONFIGS, GET_ACTIVE_CONFIG, - SET_ACTIVE_CONFIG, - CONNECT_DISPLAY_UNUSED, // unused, fails permissions check + GET_DISPLAY_STATE, CAPTURE_SCREEN, CAPTURE_LAYERS, CLEAR_ANIMATION_FRAME_STATS, @@ -485,12 +586,19 @@ public: GET_PHYSICAL_DISPLAY_IDS, ADD_REGION_SAMPLING_LISTENER, REMOVE_REGION_SAMPLING_LISTENER, - SET_ALLOWED_DISPLAY_CONFIGS, - GET_ALLOWED_DISPLAY_CONFIGS, + SET_DESIRED_DISPLAY_CONFIG_SPECS, + GET_DESIRED_DISPLAY_CONFIG_SPECS, GET_DISPLAY_BRIGHTNESS_SUPPORT, SET_DISPLAY_BRIGHTNESS, CAPTURE_SCREEN_BY_ID, NOTIFY_POWER_HINT, + SET_GLOBAL_SHADOW_SETTINGS, + GET_AUTO_LOW_LATENCY_MODE_SUPPORT, + SET_AUTO_LOW_LATENCY_MODE, + GET_GAME_CONTENT_TYPE_SUPPORT, + SET_GAME_CONTENT_TYPE, + SET_FRAME_RATE, + ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN, // Always append new enum to the end. }; @@ -498,8 +606,4 @@ public: Parcel* reply, uint32_t flags = 0); }; -// ---------------------------------------------------------------------------- - -}; // namespace android - -#endif // ANDROID_GUI_ISURFACE_COMPOSER_H +} // namespace android diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h index 32ac9e8928..3afbabf1dc 100644 --- a/libs/gui/include/gui/ISurfaceComposerClient.h +++ b/libs/gui/include/gui/ISurfaceComposerClient.h @@ -33,7 +33,7 @@ public: DECLARE_META_INTERFACE(SurfaceComposerClient) // flags for createSurface() - enum { // (keep in sync with Surface.java) + enum { // (keep in sync with SurfaceControl.java) eHidden = 0x00000004, eDestroyBackbuffer = 0x00000020, eSecure = 0x00000080, @@ -42,9 +42,10 @@ public: eProtectedByApp = 0x00000800, eProtectedByDRM = 0x00001000, eCursorWindow = 0x00002000, + eNoColorFill = 0x00004000, eFXSurfaceBufferQueue = 0x00000000, - eFXSurfaceColor = 0x00020000, + eFXSurfaceEffect = 0x00020000, eFXSurfaceBufferState = 0x00040000, eFXSurfaceContainer = 0x00080000, eFXSurfaceMask = 0x000F0000, @@ -56,7 +57,7 @@ public: virtual status_t createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags, const sp<IBinder>& parent, LayerMetadata metadata, sp<IBinder>* handle, - sp<IGraphicBufferProducer>* gbp) = 0; + sp<IGraphicBufferProducer>* gbp, uint32_t* outTransformHint) = 0; /* * Requires ACCESS_SURFACE_FLINGER permission @@ -65,7 +66,8 @@ public: PixelFormat format, uint32_t flags, const sp<IGraphicBufferProducer>& parent, LayerMetadata metadata, sp<IBinder>* handle, - sp<IGraphicBufferProducer>* gbp) = 0; + sp<IGraphicBufferProducer>* gbp, + uint32_t* outTransformHint) = 0; /* * Requires ACCESS_SURFACE_FLINGER permission @@ -76,6 +78,8 @@ public: * Requires ACCESS_SURFACE_FLINGER permission */ virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const = 0; + + virtual status_t mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle) = 0; }; class BnSurfaceComposerClient : public SafeBnInterface<ISurfaceComposerClient> { diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h index 774ad46b15..c58634b8a2 100644 --- a/libs/gui/include/gui/ITransactionCompletedListener.h +++ b/libs/gui/include/gui/ITransactionCompletedListener.h @@ -21,6 +21,7 @@ #include <binder/Parcelable.h> #include <binder/SafeInterface.h> +#include <gui/FrameTimestamps.h> #include <ui/Fence.h> #include <utils/Timers.h> @@ -31,21 +32,50 @@ namespace android { class ITransactionCompletedListener; +class ListenerCallbacks; using CallbackId = int64_t; +class FrameEventHistoryStats : public Parcelable { +public: + status_t writeToParcel(Parcel* output) const override; + status_t readFromParcel(const Parcel* input) override; + + FrameEventHistoryStats() = default; + FrameEventHistoryStats(uint64_t fn, const sp<Fence>& gpuCompFence, CompositorTiming compTiming, + nsecs_t refreshTime, nsecs_t dequeueReadyTime) + : frameNumber(fn), + gpuCompositionDoneFence(gpuCompFence), + compositorTiming(compTiming), + refreshStartTime(refreshTime), + dequeueReadyTime(dequeueReadyTime) {} + + uint64_t frameNumber; + sp<Fence> gpuCompositionDoneFence; + CompositorTiming compositorTiming; + nsecs_t refreshStartTime; + nsecs_t dequeueReadyTime; +}; + class SurfaceStats : public Parcelable { public: status_t writeToParcel(Parcel* output) const override; status_t readFromParcel(const Parcel* input) override; SurfaceStats() = default; - SurfaceStats(const sp<IBinder>& sc, nsecs_t time, const sp<Fence>& prevReleaseFence) - : surfaceControl(sc), acquireTime(time), previousReleaseFence(prevReleaseFence) {} + SurfaceStats(const sp<IBinder>& sc, nsecs_t time, const sp<Fence>& prevReleaseFence, + uint32_t hint, FrameEventHistoryStats frameEventStats) + : surfaceControl(sc), + acquireTime(time), + previousReleaseFence(prevReleaseFence), + transformHint(hint), + eventStats(frameEventStats) {} sp<IBinder> surfaceControl; nsecs_t acquireTime = -1; sp<Fence> previousReleaseFence; + uint32_t transformHint = 0; + FrameEventHistoryStats eventStats; }; class TransactionStats : public Parcelable { @@ -72,10 +102,10 @@ public: status_t writeToParcel(Parcel* output) const override; status_t readFromParcel(const Parcel* input) override; - static ListenerStats createEmpty(const sp<ITransactionCompletedListener>& listener, + static ListenerStats createEmpty(const sp<IBinder>& listener, const std::unordered_set<CallbackId>& callbackIds); - sp<ITransactionCompletedListener> listener; + sp<IBinder> listener; std::vector<TransactionStats> transactionStats; }; @@ -97,17 +127,59 @@ public: class ListenerCallbacks { public: - ListenerCallbacks(const sp<ITransactionCompletedListener>& listener, - const std::unordered_set<CallbackId>& callbacks) + ListenerCallbacks(const sp<IBinder>& listener, const std::unordered_set<CallbackId>& callbacks) : transactionCompletedListener(listener), callbackIds(callbacks.begin(), callbacks.end()) {} - ListenerCallbacks(const sp<ITransactionCompletedListener>& listener, - const std::vector<CallbackId>& ids) + ListenerCallbacks(const sp<IBinder>& listener, const std::vector<CallbackId>& ids) : transactionCompletedListener(listener), callbackIds(ids) {} - sp<ITransactionCompletedListener> transactionCompletedListener; + bool operator==(const ListenerCallbacks& rhs) const { + if (transactionCompletedListener != rhs.transactionCompletedListener) { + return false; + } + if (callbackIds.empty()) { + return rhs.callbackIds.empty(); + } + return callbackIds.front() == rhs.callbackIds.front(); + } + + sp<IBinder> transactionCompletedListener; std::vector<CallbackId> callbackIds; }; +struct IListenerHash { + std::size_t operator()(const sp<IBinder>& strongPointer) const { + return std::hash<IBinder*>{}(strongPointer.get()); + } +}; + +struct CallbackIdsHash { + // CallbackId vectors have several properties that let us get away with this simple hash. + // 1) CallbackIds are never 0 so if something has gone wrong and our CallbackId vector is + // empty we can still hash 0. + // 2) CallbackId vectors for the same listener either are identical or contain none of the + // same members. It is sufficient to just check the first CallbackId in the vectors. If + // they match, they are the same. If they do not match, they are not the same. + std::size_t operator()(const std::vector<CallbackId>& callbackIds) const { + return std::hash<CallbackId>{}((callbackIds.empty()) ? 0 : callbackIds.front()); + } +}; + +struct ListenerCallbacksHash { + std::size_t HashCombine(size_t value1, size_t value2) const { + return value1 ^ (value2 + 0x9e3779b9 + (value1 << 6) + (value1 >> 2)); + } + + std::size_t operator()(const ListenerCallbacks& listenerCallbacks) const { + struct IListenerHash listenerHasher; + struct CallbackIdsHash callbackIdsHasher; + + std::size_t listenerHash = listenerHasher(listenerCallbacks.transactionCompletedListener); + std::size_t callbackIdsHash = callbackIdsHasher(listenerCallbacks.callbackIds); + + return HashCombine(listenerHash, callbackIdsHash); + } +}; + } // namespace android diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index f438eb3d01..e60f6777ae 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -20,9 +20,9 @@ #include <stdint.h> #include <sys/types.h> -#include <utils/Errors.h> - +#include <android/native_window.h> #include <gui/IGraphicBufferProducer.h> +#include <gui/ITransactionCompletedListener.h> #include <math/mat4.h> #ifndef NO_INPUT @@ -34,6 +34,9 @@ #include <ui/GraphicTypes.h> #include <ui/Rect.h> #include <ui/Region.h> +#include <ui/Rotation.h> +#include <ui/Transform.h> +#include <utils/Errors.h> namespace android { @@ -71,7 +74,7 @@ struct layer_state_t { eCropChanged_legacy = 0x00000100, eDeferTransaction_legacy = 0x00000200, eOverrideScalingModeChanged = 0x00000400, - eGeometryAppliesWithResize = 0x00000800, + eShadowRadiusChanged = 0x00000800, eReparentChildren = 0x00001000, eDetachChildren = 0x00002000, eRelativeLayerChanged = 0x00004000, @@ -97,6 +100,11 @@ struct layer_state_t { eBackgroundColorChanged = 0x4'00000000, eMetadataChanged = 0x8'00000000, eColorSpaceAgnosticChanged = 0x10'00000000, + eFrameRateSelectionPriority = 0x20'00000000, + eFrameRateChanged = 0x40'00000000, + eBackgroundBlurRadiusChanged = 0x80'00000000, + eProducerDisconnect = 0x100'00000000, + eFixedTransformHintChanged = 0x200'00000000, }; layer_state_t() @@ -113,6 +121,7 @@ struct layer_state_t { reserved(0), crop_legacy(Rect::INVALID_RECT), cornerRadius(0.0f), + backgroundBlurRadius(0), frameNumber_legacy(0), overrideScalingMode(-1), transform(0), @@ -123,10 +132,14 @@ struct layer_state_t { surfaceDamageRegion(), api(-1), colorTransform(mat4()), - hasListenerCallbacks(false), bgColorAlpha(0), bgColorDataspace(ui::Dataspace::UNKNOWN), - colorSpaceAgnostic(false) { + colorSpaceAgnostic(false), + shadowRadius(0.0f), + frameRateSelectionPriority(-1), + frameRate(0.0f), + frameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT), + fixedTransformHint(ui::Transform::ROT_INVALID) { matrix.dsdx = matrix.dtdy = 1.0f; matrix.dsdy = matrix.dtdx = 0.0f; hdrMetadata.validTypes = 0; @@ -157,6 +170,7 @@ struct layer_state_t { matrix22_t matrix; Rect crop_legacy; float cornerRadius; + uint32_t backgroundBlurRadius; sp<IBinder> barrierHandle_legacy; sp<IBinder> reparentHandle; uint64_t frameNumber_legacy; @@ -186,7 +200,6 @@ struct layer_state_t { sp<NativeHandle> sidebandStream; mat4 colorTransform; - bool hasListenerCallbacks; #ifndef NO_INPUT InputWindowInfo inputInfo; #endif @@ -203,10 +216,30 @@ struct layer_state_t { // A color space agnostic layer means the color of this layer can be // interpreted in any color space. bool colorSpaceAgnostic; + + std::vector<ListenerCallbacks> listeners; + + // Draws a shadow around the surface. + float shadowRadius; + + // Priority of the layer assigned by Window Manager. + int32_t frameRateSelectionPriority; + + // Layer frame rate and compatibility. See ANativeWindow_setFrameRate(). + float frameRate; + int8_t frameRateCompatibility; + + // Set by window manager indicating the layer and all its children are + // in a different orientation than the display. The hint suggests that + // the graphic producers should receive a transform hint as if the + // display was in this orientation. When the display changes to match + // the layer orientation, the graphic producer may not need to allocate + // a buffer of a different size. -1 means the transform hint is not set, + // otherwise the value will be a valid ui::Rotation. + ui::Transform::RotationFlags fixedTransformHint; }; struct ComposerState { - sp<ISurfaceComposerClient> client; layer_state_t state; status_t write(Parcel& output) const; status_t read(const Parcel& input); @@ -214,15 +247,6 @@ struct ComposerState { struct DisplayState { enum { - eOrientationDefault = 0, - eOrientation90 = 1, - eOrientation180 = 2, - eOrientation270 = 3, - eOrientationUnchanged = 4, - eOrientationSwapMask = 0x01 - }; - - enum { eSurfaceChanged = 0x01, eLayerStackChanged = 0x02, eDisplayProjectionChanged = 0x04, @@ -248,7 +272,7 @@ struct DisplayState { // 0, layers will be scaled by a factor of 2 and translated by (20, 10). // When orientation is 1, layers will be additionally rotated by 90 // degrees around the origin clockwise and translated by (W, 0). - uint32_t orientation; + ui::Rotation orientation = ui::ROTATION_0; Rect viewport; Rect frame; @@ -259,12 +283,6 @@ struct DisplayState { }; struct InputWindowCommands { - struct TransferTouchFocusCommand { - sp<IBinder> fromToken; - sp<IBinder> toToken; - }; - - std::vector<TransferTouchFocusCommand> transferTouchFocusCommands; bool syncInputWindows{false}; void merge(const InputWindowCommands& other); @@ -274,8 +292,6 @@ struct InputWindowCommands { }; static inline int compare_type(const ComposerState& lhs, const ComposerState& rhs) { - if (lhs.client < rhs.client) return -1; - if (lhs.client > rhs.client) return 1; if (lhs.state.surface < rhs.state.surface) return -1; if (lhs.state.surface > rhs.state.surface) return 1; return 0; @@ -285,6 +301,12 @@ static inline int compare_type(const DisplayState& lhs, const DisplayState& rhs) return compare_type(lhs.token, rhs.token); } +// Returns true if the frameRate and compatibility are valid values, false +// othwerise. If either of the params are invalid, an error log is printed, and +// functionName is added to the log to indicate which function call failed. +// functionName can be null. +bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* functionName); + }; // namespace android #endif // ANDROID_SF_LAYER_STATE_H diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index a5641b07e5..49c83da319 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -21,16 +21,15 @@ #include <gui/HdrMetadata.h> #include <gui/IGraphicBufferProducer.h> #include <gui/IProducerListener.h> - +#include <system/window.h> #include <ui/ANativeObjectBase.h> #include <ui/GraphicTypes.h> #include <ui/Region.h> - #include <utils/Condition.h> #include <utils/Mutex.h> #include <utils/RefBase.h> -#include <system/window.h> +#include <shared_mutex> namespace android { @@ -179,8 +178,7 @@ public: status_t getUniqueId(uint64_t* outId) const; status_t getConsumerUsage(uint64_t* outUsage) const; - // Returns the CLOCK_MONOTONIC start time of the last dequeueBuffer call - nsecs_t getLastDequeueStartTime() const; + status_t setFrameRate(float frameRate, int8_t compatibility); protected: virtual ~Surface(); @@ -205,6 +203,14 @@ private: ANativeWindowBuffer* buffer, int fenceFd); static int hook_setSwapInterval(ANativeWindow* window, int interval); + static int cancelBufferInternal(ANativeWindow* window, ANativeWindowBuffer* buffer, + int fenceFd); + static int dequeueBufferInternal(ANativeWindow* window, ANativeWindowBuffer** buffer, + int* fenceFd); + static int performInternal(ANativeWindow* window, int operation, va_list args); + static int queueBufferInternal(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd); + static int queryInternal(const ANativeWindow* window, int what, int* value); + static int hook_cancelBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer); static int hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, @@ -246,6 +252,18 @@ private: int dispatchGetWideColorSupport(va_list args); int dispatchGetHdrSupport(va_list args); int dispatchGetConsumerUsage64(va_list args); + int dispatchSetAutoPrerotation(va_list args); + int dispatchGetLastDequeueStartTime(va_list args); + int dispatchSetDequeueTimeout(va_list args); + int dispatchGetLastDequeueDuration(va_list args); + int dispatchGetLastQueueDuration(va_list args); + int dispatchSetFrameRate(va_list args); + int dispatchAddCancelInterceptor(va_list args); + int dispatchAddDequeueInterceptor(va_list args); + int dispatchAddPerformInterceptor(va_list args); + int dispatchAddQueueInterceptor(va_list args); + int dispatchAddQueryInterceptor(va_list args); + int dispatchGetLastQueuedBuffer(va_list args); bool transformToDisplayInverse(); protected: @@ -281,6 +299,7 @@ public: virtual int setAsyncMode(bool async); virtual int setSharedBufferMode(bool sharedBufferMode); virtual int setAutoRefresh(bool autoRefresh); + virtual int setAutoPrerotation(bool autoPrerotation); virtual int setBuffersDimensions(uint32_t width, uint32_t height); virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds); virtual int unlockAndPost(); @@ -450,6 +469,20 @@ protected: // member variables are accessed. mutable Mutex mMutex; + // mInterceptorMutex is the mutex guarding interceptors. + mutable std::shared_mutex mInterceptorMutex; + + ANativeWindow_cancelBufferInterceptor mCancelInterceptor = nullptr; + void* mCancelInterceptorData = nullptr; + ANativeWindow_dequeueBufferInterceptor mDequeueInterceptor = nullptr; + void* mDequeueInterceptorData = nullptr; + ANativeWindow_performInterceptor mPerformInterceptor = nullptr; + void* mPerformInterceptorData = nullptr; + ANativeWindow_queueBufferInterceptor mQueueInterceptor = nullptr; + void* mQueueInterceptorData = nullptr; + ANativeWindow_queryInterceptor mQueryInterceptor = nullptr; + void* mQueryInterceptorData = nullptr; + // must be used from the lock/unlock thread sp<GraphicBuffer> mLockedBuffer; sp<GraphicBuffer> mPostedBuffer; @@ -474,6 +507,7 @@ protected: // Caches the values that have been passed to the producer. bool mSharedBufferMode; bool mAutoRefresh; + bool mAutoPrerotation; // If in shared buffer mode and auto refresh is enabled, store the shared // buffer slot and return it for all calls to queue/dequeue without going @@ -506,6 +540,7 @@ protected: bool mReportRemovedBuffers = false; std::vector<sp<GraphicBuffer>> mRemovedBuffers; + int mMaxBufferCount; sp<IProducerListener> mListenerProxy; status_t getAndFlushBuffersFromSlots(const std::vector<int32_t>& slots, diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 9d96485efe..adcb8982a0 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_GUI_SURFACE_COMPOSER_CLIENT_H -#define ANDROID_GUI_SURFACE_COMPOSER_CLIENT_H +#pragma once #include <stdint.h> #include <sys/types.h> @@ -35,6 +34,7 @@ #include <ui/FrameStats.h> #include <ui/GraphicTypes.h> #include <ui/PixelFormat.h> +#include <ui/Rotation.h> #include <gui/CpuConsumer.h> #include <gui/ISurfaceComposer.h> @@ -45,25 +45,31 @@ namespace android { -// --------------------------------------------------------------------------- - -struct DisplayInfo; class HdrCapabilities; class ISurfaceComposerClient; class IGraphicBufferProducer; class IRegionSamplingListener; class Region; -// --------------------------------------------------------------------------- - struct SurfaceControlStats { - SurfaceControlStats(const sp<SurfaceControl>& sc, nsecs_t time, - const sp<Fence>& prevReleaseFence) - : surfaceControl(sc), acquireTime(time), previousReleaseFence(prevReleaseFence) {} + SurfaceControlStats(const sp<SurfaceControl>& sc, nsecs_t latchTime, nsecs_t acquireTime, + const sp<Fence>& presentFence, const sp<Fence>& prevReleaseFence, + uint32_t hint, FrameEventHistoryStats eventStats) + : surfaceControl(sc), + latchTime(latchTime), + acquireTime(acquireTime), + presentFence(presentFence), + previousReleaseFence(prevReleaseFence), + transformHint(hint), + frameEventStats(eventStats) {} sp<SurfaceControl> surfaceControl; + nsecs_t latchTime = -1; nsecs_t acquireTime = -1; + sp<Fence> presentFence; sp<Fence> previousReleaseFence; + uint32_t transformHint = 0; + FrameEventHistoryStats frameEventStats; }; using TransactionCompletedCallbackTakesContext = @@ -97,33 +103,34 @@ public: status_t linkToComposerDeath(const sp<IBinder::DeathRecipient>& recipient, void* cookie = nullptr, uint32_t flags = 0); - // Get a list of supported configurations for a given display - static status_t getDisplayConfigs(const sp<IBinder>& display, - Vector<DisplayInfo>* configs); - - // Get the DisplayInfo for the currently-active configuration - static status_t getDisplayInfo(const sp<IBinder>& display, - DisplayInfo* info); + // Get transactional state of given display. + static status_t getDisplayState(const sp<IBinder>& display, ui::DisplayState*); - // Get the index of the current active configuration (relative to the list - // returned by getDisplayInfo) - static int getActiveConfig(const sp<IBinder>& display); + // Get immutable information about given physical display. + static status_t getDisplayInfo(const sp<IBinder>& display, DisplayInfo*); - // Set a new active configuration using an index relative to the list - // returned by getDisplayInfo - static status_t setActiveConfig(const sp<IBinder>& display, int id); + // Get configurations supported by given physical display. + static status_t getDisplayConfigs(const sp<IBinder>& display, Vector<DisplayConfig>*); - // Sets the allowed display configurations to be used. - // The allowedConfigs in a vector of indexes corresponding to the configurations - // returned from getDisplayConfigs(). - static status_t setAllowedDisplayConfigs(const sp<IBinder>& displayToken, - const std::vector<int32_t>& allowedConfigs); + // Get the ID of the active DisplayConfig, as getDisplayConfigs index. + static int getActiveConfig(const sp<IBinder>& display); - // Returns the allowed display configurations currently set. - // The allowedConfigs in a vector of indexes corresponding to the configurations - // returned from getDisplayConfigs(). - static status_t getAllowedDisplayConfigs(const sp<IBinder>& displayToken, - std::vector<int32_t>* outAllowedConfigs); + // Shorthand for getDisplayConfigs element at getActiveConfig index. + static status_t getActiveDisplayConfig(const sp<IBinder>& display, DisplayConfig*); + + // Sets the refresh rate boundaries for the display. + static status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken, + int32_t defaultConfig, float primaryRefreshRateMin, + float primaryRefreshRateMax, + float appRequestRefreshRateMin, + float appRequestRefreshRateMax); + // Gets the refresh rate boundaries for the display. + static status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken, + int32_t* outDefaultConfig, + float* outPrimaryRefreshRateMin, + float* outPrimaryRefreshRateMax, + float* outAppRequestRefreshRateMin, + float* outAppRequestRefreshRateMax); // Gets the list of supported color modes for the given display static status_t getDisplayColorModes(const sp<IBinder>& display, @@ -140,6 +147,21 @@ public: static status_t setActiveColorMode(const sp<IBinder>& display, ui::ColorMode colorMode); + // Reports whether the connected display supports Auto Low Latency Mode + static bool getAutoLowLatencyModeSupport(const sp<IBinder>& display); + + // Switches on/off Auto Low Latency Mode on the connected display. This should only be + // called if the connected display supports Auto Low Latency Mode as reported by + // #getAutoLowLatencyModeSupport + static void setAutoLowLatencyMode(const sp<IBinder>& display, bool on); + + // Reports whether the connected display supports Game content type + static bool getGameContentTypeSupport(const sp<IBinder>& display); + + // Turns Game mode on/off on the connected display. This should only be called + // if the display supports Game content type, as reported by #getGameContentTypeSupport + static void setGameContentType(const sp<IBinder>& display, bool on); + /* Triggers screen on/off or low power mode and waits for it to complete */ static void setDisplayPowerMode(const sp<IBinder>& display, int mode); @@ -160,13 +182,6 @@ public: static bool getProtectedContentSupport(); /** - * Called from SurfaceControl d'tor to 'destroy' the surface (or rather, reparent it - * to null), but without needing an sp<SurfaceControl> to avoid infinite ressurection. - */ - static void doDropReferenceTransaction(const sp<IBinder>& handle, - const sp<ISurfaceComposerClient>& client); - - /** * Uncaches a buffer in ISurfaceComposer. It must be uncached via a transaction so that it is * in order with other transactions that use buffers. */ @@ -211,6 +226,27 @@ public: */ static status_t notifyPowerHint(int32_t hintId); + /* + * Sets the global configuration for all the shadows drawn by SurfaceFlinger. Shadow follows + * material design guidelines. + * + * ambientColor + * Color to the ambient shadow. The alpha is premultiplied. + * + * spotColor + * Color to the spot shadow. The alpha is premultiplied. The position of the spot shadow + * depends on the light position. + * + * lightPosY/lightPosZ + * Position of the light used to cast the spot shadow. The X value is always the display + * width / 2. + * + * lightRadius + * Radius of the light casting the shadow. + */ + static status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, + float lightPosY, float lightPosZ, float lightRadius); + // ------------------------------------------------------------------------ // surface creation / destruction @@ -223,18 +259,18 @@ public: PixelFormat format, // pixel-format desired uint32_t flags = 0, // usage flags SurfaceControl* parent = nullptr, // parent - LayerMetadata metadata = LayerMetadata() // metadata - ); + LayerMetadata metadata = LayerMetadata(), // metadata + uint32_t* outTransformHint = nullptr); status_t createSurfaceChecked(const String8& name, // name of the surface uint32_t w, // width in pixel uint32_t h, // height in pixel PixelFormat format, // pixel-format desired sp<SurfaceControl>* outSurface, - uint32_t flags = 0, // usage flags - SurfaceControl* parent = nullptr, // parent - LayerMetadata metadata = LayerMetadata() // metadata - ); + uint32_t flags = 0, // usage flags + SurfaceControl* parent = nullptr, // parent + LayerMetadata metadata = LayerMetadata(), // metadata + uint32_t* outTransformHint = nullptr); //! Create a surface sp<SurfaceControl> createWithSurfaceParent(const String8& name, // name of the surface @@ -243,8 +279,19 @@ public: PixelFormat format, // pixel-format desired uint32_t flags = 0, // usage flags Surface* parent = nullptr, // parent - LayerMetadata metadata = LayerMetadata() // metadata - ); + LayerMetadata metadata = LayerMetadata(), // metadata + uint32_t* outTransformHint = nullptr); + + // Creates a mirrored hierarchy for the mirrorFromSurface. This returns a SurfaceControl + // which is a parent of the root of the mirrored hierarchy. + // + // Real Hierarchy Mirror + // SC (value that's returned) + // | + // A A' + // | | + // B B' + sp<SurfaceControl> mirrorSurface(SurfaceControl* mirrorFromSurface); //! Create a virtual display static sp<IBinder> createDisplay(const String8& displayName, bool secure); @@ -270,6 +317,12 @@ public: } }; + struct IBinderHash { + std::size_t operator()(const sp<IBinder>& iBinder) const { + return std::hash<IBinder*>{}(iBinder.get()); + } + }; + struct TCLHash { std::size_t operator()(const sp<ITransactionCompletedListener>& tcl) const { return std::hash<IBinder*>{}((tcl) ? IInterface::asBinder(tcl).get() : nullptr); @@ -285,16 +338,19 @@ public: std::unordered_set<sp<SurfaceControl>, SCHash> surfaceControls; }; - class Transaction { - std::unordered_map<sp<SurfaceControl>, ComposerState, SCHash> mComposerStates; + class Transaction : public Parcelable { + protected: + std::unordered_map<sp<IBinder>, ComposerState, IBinderHash> mComposerStates; SortedVector<DisplayState > mDisplayStates; std::unordered_map<sp<ITransactionCompletedListener>, CallbackInfo, TCLHash> mListenerCallbacks; - uint32_t mForceSynchronous = 0; - uint32_t mTransactionNestCount = 0; - bool mAnimation = false; - bool mEarlyWakeup = false; + uint32_t mForceSynchronous = 0; + uint32_t mTransactionNestCount = 0; + bool mAnimation = false; + bool mEarlyWakeup = false; + bool mExplicitEarlyWakeupStart = false; + bool mExplicitEarlyWakeupEnd = false; // Indicates that the Transaction contains a buffer that should be cached bool mContainsBuffer = false; @@ -314,7 +370,10 @@ public: InputWindowCommands mInputWindowCommands; int mStatus = NO_ERROR; - layer_state_t* getLayerState(const sp<SurfaceControl>& sc); + layer_state_t* getLayerState(const sp<IBinder>& surfaceHandle); + layer_state_t* getLayerState(const sp<SurfaceControl>& sc) { + return getLayerState(sc->getHandle()); + } DisplayState& getDisplayState(const sp<IBinder>& token); void cacheBuffers(); @@ -325,6 +384,15 @@ public: virtual ~Transaction() = default; Transaction(Transaction const& other); + // Factory method that creates a new Transaction instance from the parcel. + static std::unique_ptr<Transaction> createFromParcel(const Parcel* parcel); + + status_t writeToParcel(Parcel* parcel) const override; + status_t readFromParcel(const Parcel* parcel) override; + + // Clears the contents of the transaction without applying it. + void clear(); + status_t apply(bool synchronous = false); // Merge another transaction in to this one, clearing other // as if it had been applied. @@ -361,6 +429,8 @@ public: float dsdx, float dtdx, float dtdy, float dsdy); Transaction& setCrop_legacy(const sp<SurfaceControl>& sc, const Rect& crop); Transaction& setCornerRadius(const sp<SurfaceControl>& sc, float cornerRadius); + Transaction& setBackgroundBlurRadius(const sp<SurfaceControl>& sc, + int backgroundBlurRadius); Transaction& setLayerStack(const sp<SurfaceControl>& sc, uint32_t layerStack); Transaction& setMetadata(const sp<SurfaceControl>& sc, uint32_t key, const Parcel& p); // Defers applying any changes made in this transaction until the Layer @@ -409,9 +479,15 @@ public: Transaction& setDesiredPresentTime(nsecs_t desiredPresentTime); Transaction& setColorSpaceAgnostic(const sp<SurfaceControl>& sc, const bool agnostic); + // Sets information about the priority of the frame. + Transaction& setFrameRateSelectionPriority(const sp<SurfaceControl>& sc, int32_t priority); + Transaction& addTransactionCompletedCallback( TransactionCompletedCallbackTakesContext callback, void* callbackContext); + // ONLY FOR BLAST ADAPTER + Transaction& notifyProducerDisconnect(const sp<SurfaceControl>& sc); + // Detaches all child surfaces (and their children recursively) // from their SurfaceControl. // The child SurfaceControls will not throw exceptions or return errors, @@ -429,15 +505,8 @@ public: Transaction& setOverrideScalingMode(const sp<SurfaceControl>& sc, int32_t overrideScalingMode); - // If the size changes in this transaction, all geometry updates specified - // in this transaction will not complete until a buffer of the new size - // arrives. As some elements normally apply immediately, this enables - // freezing the total geometry of a surface until a resize is completed. - Transaction& setGeometryAppliesWithResize(const sp<SurfaceControl>& sc); - #ifndef NO_INPUT Transaction& setInputWindowInfo(const sp<SurfaceControl>& sc, const InputWindowInfo& info); - Transaction& transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken); Transaction& syncInputWindows(); #endif @@ -447,6 +516,18 @@ public: Transaction& setGeometry(const sp<SurfaceControl>& sc, const Rect& source, const Rect& dst, int transform); + Transaction& setShadowRadius(const sp<SurfaceControl>& sc, float cornerRadius); + + Transaction& setFrameRate(const sp<SurfaceControl>& sc, float frameRate, + int8_t compatibility); + + // Set by window manager indicating the layer and all its children are + // in a different orientation than the display. The hint suggests that + // the graphic producers should receive a transform hint as if the + // display was in this orientation. When the display changes to match + // the layer orientation, the graphic producer may not need to allocate + // a buffer of a different size. + Transaction& setFixedTransformHint(const sp<SurfaceControl>& sc, int32_t transformHint); status_t setDisplaySurface(const sp<IBinder>& token, const sp<IGraphicBufferProducer>& bufferProducer); @@ -463,13 +544,13 @@ public: * mapped to. displayRect is specified post-orientation, that is * it uses the orientation seen by the end-user. */ - void setDisplayProjection(const sp<IBinder>& token, - uint32_t orientation, - const Rect& layerStackRect, - const Rect& displayRect); + void setDisplayProjection(const sp<IBinder>& token, ui::Rotation orientation, + const Rect& layerStackRect, const Rect& displayRect); void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height); void setAnimationTransaction(); void setEarlyWakeup(); + void setExplicitEarlyWakeupStart(); + void setExplicitEarlyWakeupEnd(); }; status_t clearLayerFrameStats(const sp<IBinder>& token) const; @@ -480,10 +561,8 @@ public: static status_t getHdrCapabilities(const sp<IBinder>& display, HdrCapabilities* outCapabilities); - static void setDisplayProjection(const sp<IBinder>& token, - uint32_t orientation, - const Rect& layerStackRect, - const Rect& displayRect); + static void setDisplayProjection(const sp<IBinder>& token, ui::Rotation orientation, + const Rect& layerStackRect, const Rect& displayRect); inline sp<ISurfaceComposerClient> getClient() { return mClient; } @@ -515,23 +594,23 @@ class ScreenshotClient { public: // if cropping isn't required, callers may pass in a default Rect, e.g.: // capture(display, producer, Rect(), reqWidth, ...); - static status_t capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace, - const ui::PixelFormat reqPixelFormat, Rect sourceCrop, + static status_t capture(const sp<IBinder>& display, ui::Dataspace reqDataSpace, + ui::PixelFormat reqPixelFormat, const Rect& sourceCrop, uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform, - uint32_t rotation, bool captureSecureLayers, + ui::Rotation rotation, bool captureSecureLayers, sp<GraphicBuffer>* outBuffer, bool& outCapturedSecureLayers); - static status_t capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace, - const ui::PixelFormat reqPixelFormat, Rect sourceCrop, + static status_t capture(const sp<IBinder>& display, ui::Dataspace reqDataSpace, + ui::PixelFormat reqPixelFormat, const Rect& sourceCrop, uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform, - uint32_t rotation, sp<GraphicBuffer>* outBuffer); + ui::Rotation rotation, sp<GraphicBuffer>* outBuffer); static status_t capture(uint64_t displayOrLayerStack, ui::Dataspace* outDataspace, sp<GraphicBuffer>* outBuffer); - static status_t captureLayers(const sp<IBinder>& layerHandle, const ui::Dataspace reqDataSpace, - const ui::PixelFormat reqPixelFormat, Rect sourceCrop, + static status_t captureLayers(const sp<IBinder>& layerHandle, ui::Dataspace reqDataSpace, + ui::PixelFormat reqPixelFormat, const Rect& sourceCrop, float frameScale, sp<GraphicBuffer>* outBuffer); static status_t captureChildLayers( - const sp<IBinder>& layerHandle, const ui::Dataspace reqDataSpace, - const ui::PixelFormat reqPixelFormat, Rect sourceCrop, + const sp<IBinder>& layerHandle, ui::Dataspace reqDataSpace, + ui::PixelFormat reqPixelFormat, const Rect& sourceCrop, const std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>>& excludeHandles, float frameScale, sp<GraphicBuffer>* outBuffer); @@ -550,15 +629,10 @@ class TransactionCompletedListener : public BnTransactionCompletedListener { CallbackId mCallbackIdCounter GUARDED_BY(mMutex) = 1; - struct IBinderHash { - std::size_t operator()(const sp<IBinder>& iBinder) const { - return std::hash<IBinder*>{}(iBinder.get()); - } - }; - struct CallbackTranslation { TransactionCompletedCallback callbackFunction; - std::unordered_map<sp<IBinder>, sp<SurfaceControl>, IBinderHash> surfaceControls; + std::unordered_map<sp<IBinder>, sp<SurfaceControl>, SurfaceComposerClient::IBinderHash> + surfaceControls; }; std::unordered_map<CallbackId, CallbackTranslation> mCallbacks GUARDED_BY(mMutex); @@ -581,8 +655,4 @@ public: void onTransactionCompleted(ListenerStats stats) override; }; -// --------------------------------------------------------------------------- - -}; // namespace android - -#endif // ANDROID_GUI_SURFACE_COMPOSER_CLIENT_H +} // namespace android diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h index 23bfc0256b..ac2bbccfd2 100644 --- a/libs/gui/include/gui/SurfaceControl.h +++ b/libs/gui/include/gui/SurfaceControl.h @@ -44,7 +44,7 @@ class SurfaceComposerClient; class SurfaceControl : public RefBase { public: - static sp<SurfaceControl> readFromParcel(Parcel* parcel); + static sp<SurfaceControl> readFromParcel(const Parcel* parcel); void writeToParcel(Parcel* parcel); static bool isValid(const sp<SurfaceControl>& surface) { @@ -58,10 +58,6 @@ public: static bool isSameSurface( const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs); - // Release the handles assosciated with the SurfaceControl, without reparenting - // them off-screen. At the moment if this isn't executed before ~SurfaceControl - // is called then the destructor will reparent the layer off-screen for you. - void release(); // Reparent off-screen and release. This is invoked by the destructor. void destroy(); @@ -81,11 +77,15 @@ public: status_t getLayerFrameStats(FrameStats* outStats) const; sp<SurfaceComposerClient> getClient() const; - + + uint32_t getTransformHint() const; + + void setTransformHint(uint32_t hint); + explicit SurfaceControl(const sp<SurfaceControl>& other); SurfaceControl(const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle, - const sp<IGraphicBufferProducer>& gbp, bool owned); + const sp<IGraphicBufferProducer>& gbp, uint32_t transformHint = 0); private: // can't be copied @@ -105,7 +105,7 @@ private: sp<IGraphicBufferProducer> mGraphicBufferProducer; mutable Mutex mLock; mutable sp<Surface> mSurfaceData; - bool mOwned; + uint32_t mTransformHint; }; }; // namespace android diff --git a/libs/gui/include/gui/bufferqueue/1.0/Conversion.h b/libs/gui/include/gui/bufferqueue/1.0/Conversion.h index 627845c0ea..811dcbeb02 100644 --- a/libs/gui/include/gui/bufferqueue/1.0/Conversion.h +++ b/libs/gui/include/gui/bufferqueue/1.0/Conversion.h @@ -25,8 +25,6 @@ #include <hidl/MQDescriptor.h> #include <hidl/Status.h> -#include <binder/Binder.h> -#include <binder/Status.h> #include <ui/FenceTime.h> #include <cutils/native_handle.h> #include <gui/IGraphicBufferProducer.h> @@ -127,15 +125,6 @@ int native_handle_read_fd(native_handle_t const* nh, int index = 0); */ /** - * \brief Convert `Return<void>` to `binder::Status`. - * - * \param[in] t The source `Return<void>`. - * \return The corresponding `binder::Status`. - */ -// convert: Return<void> -> ::android::binder::Status -::android::binder::Status toBinderStatus(Return<void> const& t); - -/** * \brief Convert `Return<void>` to `status_t`. This is for legacy binder calls. * * \param[in] t The source `Return<void>`. diff --git a/libs/gui/include/gui/bufferqueue/1.0/H2BProducerListener.h b/libs/gui/include/gui/bufferqueue/1.0/H2BProducerListener.h index 211fdd5351..cda5103334 100644 --- a/libs/gui/include/gui/bufferqueue/1.0/H2BProducerListener.h +++ b/libs/gui/include/gui/bufferqueue/1.0/H2BProducerListener.h @@ -34,7 +34,12 @@ using HProducerListener = ::android::hardware::graphics::bufferqueue::V1_0:: using BProducerListener = ::android::IProducerListener; class H2BProducerListener +#ifndef NO_BINDER : public H2BConverter<HProducerListener, BnProducerListener> { +#else + : public BProducerListener { + sp<HProducerListener> mBase; +#endif public: H2BProducerListener(sp<HProducerListener> const& base); virtual void onBufferReleased() override; diff --git a/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h index 029dcc047f..004d87574a 100644 --- a/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h +++ b/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h @@ -49,15 +49,16 @@ typedef ::android::hardware::graphics::bufferqueue::V1_0:: typedef ::android::IGraphicBufferProducer BGraphicBufferProducer; typedef ::android::IProducerListener BProducerListener; -using ::android::BnGraphicBufferProducer; #ifndef LOG -struct LOG_dummy { +struct LOG_stub { template <typename T> - LOG_dummy& operator<< (const T&) { return *this; } + LOG_stub& operator<<(const T&) { + return *this; + } }; -#define LOG(x) LOG_dummy() +#define LOG(x) LOG_stub() #endif // Instantiate only if HGraphicBufferProducer is base of BASE. diff --git a/libs/gui/include/gui/bufferqueue/1.0/WProducerListener.h b/libs/gui/include/gui/bufferqueue/1.0/WProducerListener.h index 51dff5b8be..197db26444 100644 --- a/libs/gui/include/gui/bufferqueue/1.0/WProducerListener.h +++ b/libs/gui/include/gui/bufferqueue/1.0/WProducerListener.h @@ -20,7 +20,6 @@ #include <hidl/MQDescriptor.h> #include <hidl/Status.h> -#include <binder/IBinder.h> #include <gui/IProducerListener.h> #include <android/hardware/graphics/bufferqueue/1.0/IProducerListener.h> @@ -55,6 +54,7 @@ public: LWProducerListener(sp<HProducerListener> const& base); void onBufferReleased() override; bool needsReleaseNotify() override; + void onBuffersDiscarded(const std::vector<int32_t>& slots) override; }; } // namespace android diff --git a/libs/gui/include/gui/bufferqueue/2.0/B2HGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/2.0/B2HGraphicBufferProducer.h index 1c58167752..16d054ba9e 100644 --- a/libs/gui/include/gui/bufferqueue/2.0/B2HGraphicBufferProducer.h +++ b/libs/gui/include/gui/bufferqueue/2.0/B2HGraphicBufferProducer.h @@ -45,6 +45,7 @@ using ::android::hardware::hidl_string; using ::android::hardware::hidl_vec; using ::android::hardware::graphics::common::V1_2::HardwareBuffer; +struct Obituary; class B2HGraphicBufferProducer : public HGraphicBufferProducer { public: @@ -108,6 +109,7 @@ public: protected: sp<BGraphicBufferProducer> mBase; + sp<Obituary> mObituary; }; diff --git a/libs/gui/include/gui/bufferqueue/2.0/H2BProducerListener.h b/libs/gui/include/gui/bufferqueue/2.0/H2BProducerListener.h index 898920bf8a..92650b701b 100644 --- a/libs/gui/include/gui/bufferqueue/2.0/H2BProducerListener.h +++ b/libs/gui/include/gui/bufferqueue/2.0/H2BProducerListener.h @@ -33,12 +33,20 @@ using HProducerListener = ::android::hardware::graphics::bufferqueue::V2_0:: using BProducerListener = ::android::IProducerListener; +#ifndef NO_BINDER class H2BProducerListener : public H2BConverter<HProducerListener, BnProducerListener> { +#else +class H2BProducerListener + : public BProducerListener { + sp<HProducerListener> mBase; + +#endif public: H2BProducerListener(sp<HProducerListener> const& base); virtual void onBufferReleased() override; virtual bool needsReleaseNotify() override; + virtual void onBuffersDiscarded(const std::vector<int32_t>& slots) override; }; } // namespace utils diff --git a/libs/gui/include/gui/mock/GraphicBufferConsumer.h b/libs/gui/include/gui/mock/GraphicBufferConsumer.h new file mode 100644 index 0000000000..98f24c2d44 --- /dev/null +++ b/libs/gui/include/gui/mock/GraphicBufferConsumer.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2018 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <gmock/gmock.h> + +#include <gui/IGraphicBufferConsumer.h> + +#include <utils/RefBase.h> + +namespace android { +namespace mock { + +class GraphicBufferConsumer : public BnGraphicBufferConsumer, public virtual android::RefBase { +public: + GraphicBufferConsumer(); + ~GraphicBufferConsumer() override; + + MOCK_METHOD3(acquireBuffer, status_t(BufferItem*, nsecs_t, uint64_t)); + MOCK_METHOD1(detachBuffer, status_t(int)); + MOCK_METHOD2(attachBuffer, status_t(int*, const sp<GraphicBuffer>&)); + MOCK_METHOD5(releaseBuffer, status_t(int, uint64_t, EGLDisplay, EGLSyncKHR, const sp<Fence>&)); + MOCK_METHOD2(consumerConnect, status_t(const sp<IConsumerListener>&, bool)); + MOCK_METHOD0(consumerDisconnect, status_t()); + MOCK_METHOD1(getReleasedBuffers, status_t(uint64_t*)); + MOCK_METHOD2(setDefaultBufferSize, status_t(uint32_t, uint32_t)); + MOCK_METHOD1(setMaxBufferCount, status_t(int)); + MOCK_METHOD1(setMaxAcquiredBufferCount, status_t(int)); + MOCK_METHOD1(setConsumerName, status_t(const String8&)); + MOCK_METHOD1(setDefaultBufferFormat, status_t(PixelFormat)); + MOCK_METHOD1(setDefaultBufferDataSpace, status_t(android_dataspace)); + MOCK_METHOD1(setConsumerUsageBits, status_t(uint64_t)); + MOCK_METHOD1(setConsumerIsProtected, status_t(bool)); + MOCK_METHOD1(setTransformHint, status_t(uint32_t)); + MOCK_CONST_METHOD1(getSidebandStream, status_t(sp<NativeHandle>*)); + MOCK_METHOD2(getOccupancyHistory, status_t(bool, std::vector<OccupancyTracker::Segment>*)); + MOCK_METHOD0(discardFreeBuffers, status_t()); + MOCK_CONST_METHOD2(dumpState, status_t(const String8&, String8*)); +}; + +} // namespace mock +} // namespace android diff --git a/libs/gui/include/gui/mock/GraphicBufferProducer.h b/libs/gui/include/gui/mock/GraphicBufferProducer.h new file mode 100644 index 0000000000..c98f39f43c --- /dev/null +++ b/libs/gui/include/gui/mock/GraphicBufferProducer.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2018 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <gmock/gmock.h> + +#include <gui/IGraphicBufferProducer.h> + +#include <utils/RefBase.h> + +namespace android { +namespace mock { + +class GraphicBufferProducer : public BnGraphicBufferProducer, public virtual android::RefBase { +public: + GraphicBufferProducer(); + ~GraphicBufferProducer() override; + + MOCK_METHOD2(requestBuffer, status_t(int, sp<GraphicBuffer>*)); + MOCK_METHOD1(setMaxDequeuedBufferCount, status_t(int)); + MOCK_METHOD1(setAsyncMode, status_t(bool)); + MOCK_METHOD8(dequeueBuffer, + status_t(int*, sp<Fence>*, uint32_t, uint32_t, PixelFormat, uint64_t, uint64_t*, + FrameEventHistoryDelta*)); + MOCK_METHOD1(detachBuffer, status_t(int)); + MOCK_METHOD2(detachNextBuffer, status_t(sp<GraphicBuffer>*, sp<Fence>*)); + MOCK_METHOD2(attachBuffer, status_t(int*, const sp<GraphicBuffer>&)); + MOCK_METHOD3(queueBuffer, status_t(int, const QueueBufferInput&, QueueBufferOutput*)); + MOCK_METHOD2(cancelBuffer, status_t(int, const sp<Fence>&)); + MOCK_METHOD2(query, int(int, int*)); + MOCK_METHOD4(connect, status_t(const sp<IProducerListener>&, int, bool, QueueBufferOutput*)); + MOCK_METHOD2(disconnect, status_t(int, DisconnectMode)); + MOCK_METHOD1(setSidebandStream, status_t(const sp<NativeHandle>&)); + MOCK_METHOD4(allocateBuffers, void(uint32_t, uint32_t, PixelFormat, uint64_t)); + MOCK_METHOD1(allowAllocation, status_t(bool)); + MOCK_METHOD1(setGenerationNumber, status_t(uint32_t)); + MOCK_CONST_METHOD0(getConsumerName, String8()); + MOCK_METHOD1(setSharedBufferMode, status_t(bool)); + MOCK_METHOD1(setAutoRefresh, status_t(bool)); + MOCK_METHOD1(setDequeueTimeout, status_t(nsecs_t)); + MOCK_METHOD3(getLastQueuedBuffer, status_t(sp<GraphicBuffer>*, sp<Fence>*, float[16])); + MOCK_METHOD1(getFrameTimestamps, void(FrameEventHistoryDelta*)); + MOCK_CONST_METHOD1(getUniqueId, status_t(uint64_t*)); + MOCK_CONST_METHOD1(getConsumerUsage, status_t(uint64_t*)); +}; + +} // namespace mock +} // namespace android diff --git a/libs/gui/mock/GraphicBufferConsumer.cpp b/libs/gui/mock/GraphicBufferConsumer.cpp new file mode 100644 index 0000000000..4a6c0815e1 --- /dev/null +++ b/libs/gui/mock/GraphicBufferConsumer.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2018 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <gui/mock/GraphicBufferConsumer.h> + +namespace android { +namespace mock { + +// Explicit default instantiation is recommended. +GraphicBufferConsumer::GraphicBufferConsumer() = default; +GraphicBufferConsumer::~GraphicBufferConsumer() = default; + +} // namespace mock +} // namespace android
\ No newline at end of file diff --git a/libs/gui/mock/GraphicBufferProducer.cpp b/libs/gui/mock/GraphicBufferProducer.cpp new file mode 100644 index 0000000000..239a80a2e1 --- /dev/null +++ b/libs/gui/mock/GraphicBufferProducer.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2018 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <gui/mock/GraphicBufferProducer.h> + +namespace android { +namespace mock { + +// Explicit default instantiation is recommended. +GraphicBufferProducer::GraphicBufferProducer() = default; +GraphicBufferProducer::~GraphicBufferProducer() = default; + +} // namespace mock +} // namespace android
\ No newline at end of file diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp index cbda6b23ff..a6bcd107af 100644 --- a/libs/gui/tests/Android.bp +++ b/libs/gui/tests/Android.bp @@ -13,7 +13,8 @@ cc_test { ], srcs: [ - "BufferItemConsumer_test.cpp", + "BLASTBufferQueue_test.cpp", + "BufferItemConsumer_test.cpp", "BufferQueue_test.cpp", "CpuConsumer_test.cpp", "EndToEndNativeInputTest.cpp", @@ -38,6 +39,7 @@ cc_test { shared_libs: [ "android.hardware.configstore@1.0", "android.hardware.configstore-utils", + "libSurfaceFlingerProp", "libbase", "liblog", "libEGL", @@ -52,6 +54,8 @@ cc_test { "libutils", "libnativewindow" ], + + header_libs: ["libsurfaceflinger_headers"], } // Build a separate binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE) diff --git a/libs/gui/tests/AndroidTest.xml b/libs/gui/tests/AndroidTest.xml index c02e020be6..5e09fff6bb 100644 --- a/libs/gui/tests/AndroidTest.xml +++ b/libs/gui/tests/AndroidTest.xml @@ -18,6 +18,10 @@ <option name="cleanup" value="true" /> <option name="push" value="libgui_test->/data/local/tmp/libgui_test" /> </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.DeviceSetup"> + <option name="force-skip-system-props" value="true" /> <!-- avoid restarting device --> + <option name="screen-always-on" value="on" /> + </target_preparer> <option name="test-suite-tag" value="apct" /> <test class="com.android.tradefed.testtype.GTest" > <option name="native-test-device-path" value="/data/local/tmp" /> diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp new file mode 100644 index 0000000000..da5bbdd2e6 --- /dev/null +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -0,0 +1,729 @@ +/* + * Copyright (C) 2019 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "BLASTBufferQueue_test" + +#include <gui/BLASTBufferQueue.h> + +#include <android/hardware/graphics/common/1.2/types.h> +#include <gui/BufferQueueCore.h> +#include <gui/BufferQueueProducer.h> +#include <gui/FrameTimestamps.h> +#include <gui/IGraphicBufferProducer.h> +#include <gui/IProducerListener.h> +#include <gui/SurfaceComposerClient.h> +#include <private/gui/ComposerService.h> +#include <ui/DisplayConfig.h> +#include <ui/GraphicBuffer.h> +#include <ui/GraphicTypes.h> +#include <ui/Transform.h> + +#include <gtest/gtest.h> + +using namespace std::chrono_literals; + +namespace android { + +using Transaction = SurfaceComposerClient::Transaction; +using android::hardware::graphics::common::V1_2::BufferUsage; + +class BLASTBufferQueueHelper { +public: + BLASTBufferQueueHelper(const sp<SurfaceControl>& sc, int width, int height) { + mBlastBufferQueueAdapter = new BLASTBufferQueue(sc, width, height); + } + + void update(const sp<SurfaceControl>& sc, int width, int height) { + mBlastBufferQueueAdapter->update(sc, width, height); + } + + void setNextTransaction(Transaction* next) { + mBlastBufferQueueAdapter->setNextTransaction(next); + } + + int getWidth() { return mBlastBufferQueueAdapter->mWidth; } + + int getHeight() { return mBlastBufferQueueAdapter->mHeight; } + + Transaction* getNextTransaction() { return mBlastBufferQueueAdapter->mNextTransaction; } + + sp<IGraphicBufferProducer> getIGraphicBufferProducer() { + return mBlastBufferQueueAdapter->getIGraphicBufferProducer(); + } + + const sp<SurfaceControl> getSurfaceControl() { + return mBlastBufferQueueAdapter->mSurfaceControl; + } + + void waitForCallbacks() { + std::unique_lock lock{mBlastBufferQueueAdapter->mMutex}; + while (mBlastBufferQueueAdapter->mSubmitted.size() > 0) { + mBlastBufferQueueAdapter->mCallbackCV.wait(lock); + } + } + +private: + sp<BLASTBufferQueue> mBlastBufferQueueAdapter; +}; + +class BLASTBufferQueueTest : public ::testing::Test { +public: +protected: + BLASTBufferQueueTest() { + const ::testing::TestInfo* const testInfo = + ::testing::UnitTest::GetInstance()->current_test_info(); + ALOGV("Begin test: %s.%s", testInfo->test_case_name(), testInfo->name()); + } + + ~BLASTBufferQueueTest() { + const ::testing::TestInfo* const testInfo = + ::testing::UnitTest::GetInstance()->current_test_info(); + ALOGV("End test: %s.%s", testInfo->test_case_name(), testInfo->name()); + } + + void SetUp() { + mComposer = ComposerService::getComposerService(); + mClient = new SurfaceComposerClient(); + mDisplayToken = mClient->getInternalDisplayToken(); + ASSERT_NE(nullptr, mDisplayToken.get()); + Transaction t; + t.setDisplayLayerStack(mDisplayToken, 0); + t.apply(); + t.clear(); + + DisplayConfig config; + ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(mDisplayToken, &config)); + const ui::Size& resolution = config.resolution; + mDisplayWidth = resolution.getWidth(); + mDisplayHeight = resolution.getHeight(); + + mSurfaceControl = mClient->createSurface(String8("TestSurface"), mDisplayWidth, + mDisplayHeight, PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceBufferState, + /*parent*/ nullptr); + t.setLayerStack(mSurfaceControl, 0) + .setLayer(mSurfaceControl, std::numeric_limits<int32_t>::max()) + .setFrame(mSurfaceControl, Rect(resolution)) + .show(mSurfaceControl) + .setDataspace(mSurfaceControl, ui::Dataspace::V0_SRGB) + .apply(); + } + + void setUpProducer(BLASTBufferQueueHelper adapter, sp<IGraphicBufferProducer>& producer) { + auto igbProducer = adapter.getIGraphicBufferProducer(); + ASSERT_NE(nullptr, igbProducer.get()); + ASSERT_EQ(NO_ERROR, igbProducer->setMaxDequeuedBufferCount(2)); + IGraphicBufferProducer::QueueBufferOutput qbOutput; + ASSERT_EQ(NO_ERROR, + igbProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false, + &qbOutput)); + ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint); + producer = igbProducer; + } + + void fillBuffer(uint32_t* bufData, Rect rect, uint32_t stride, uint8_t r, uint8_t g, + uint8_t b) { + for (uint32_t row = rect.top; row < rect.bottom; row++) { + for (uint32_t col = rect.left; col < rect.right; col++) { + uint8_t* pixel = (uint8_t*)(bufData + (row * stride) + col); + *pixel = r; + *(pixel + 1) = g; + *(pixel + 2) = b; + *(pixel + 3) = 255; + } + } + } + + void fillQuadrants(sp<GraphicBuffer>& buf) { + const auto bufWidth = buf->getWidth(); + const auto bufHeight = buf->getHeight(); + uint32_t* bufData; + buf->lock(static_cast<uint32_t>(GraphicBuffer::USAGE_SW_WRITE_OFTEN), + reinterpret_cast<void**>(&bufData)); + fillBuffer(bufData, Rect(0, 0, bufWidth / 2, bufHeight / 2), buf->getStride(), 0, 0, 0); + fillBuffer(bufData, Rect(bufWidth / 2, 0, bufWidth, bufHeight / 2), buf->getStride(), 255, + 0, 0); + fillBuffer(bufData, Rect(bufWidth / 2, bufHeight / 2, bufWidth, bufHeight), + buf->getStride(), 0, 255, 0); + fillBuffer(bufData, Rect(0, bufHeight / 2, bufWidth / 2, bufHeight), buf->getStride(), 0, 0, + 255); + buf->unlock(); + } + + void checkScreenCapture(uint8_t r, uint8_t g, uint8_t b, Rect region, int32_t border = 0, + bool outsideRegion = false) { + const auto epsilon = 3; + const auto width = mScreenCaptureBuf->getWidth(); + const auto height = mScreenCaptureBuf->getHeight(); + const auto stride = mScreenCaptureBuf->getStride(); + + uint32_t* bufData; + mScreenCaptureBuf->lock(static_cast<uint32_t>(GraphicBuffer::USAGE_SW_READ_OFTEN), + reinterpret_cast<void**>(&bufData)); + + for (uint32_t row = 0; row < height; row++) { + for (uint32_t col = 0; col < width; col++) { + uint8_t* pixel = (uint8_t*)(bufData + (row * stride) + col); + bool inRegion; + if (!outsideRegion) { + inRegion = row >= region.top + border && row < region.bottom - border && + col >= region.left + border && col < region.right - border; + } else { + inRegion = row >= region.top - border && row < region.bottom + border && + col >= region.left - border && col < region.right + border; + } + if (!outsideRegion && inRegion) { + EXPECT_GE(epsilon, abs(r - *(pixel))); + EXPECT_GE(epsilon, abs(g - *(pixel + 1))); + EXPECT_GE(epsilon, abs(b - *(pixel + 2))); + } else if (outsideRegion && !inRegion) { + EXPECT_GE(epsilon, abs(r - *(pixel))); + EXPECT_GE(epsilon, abs(g - *(pixel + 1))); + EXPECT_GE(epsilon, abs(b - *(pixel + 2))); + } + } + } + mScreenCaptureBuf->unlock(); + ASSERT_EQ(false, ::testing::Test::HasFailure()); + } + + sp<SurfaceComposerClient> mClient; + sp<ISurfaceComposer> mComposer; + + sp<IBinder> mDisplayToken; + + sp<SurfaceControl> mSurfaceControl; + sp<GraphicBuffer> mScreenCaptureBuf; + + uint32_t mDisplayWidth; + uint32_t mDisplayHeight; +}; + +TEST_F(BLASTBufferQueueTest, CreateBLASTBufferQueue) { + // create BLASTBufferQueue adapter associated with this surface + BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); + ASSERT_EQ(mSurfaceControl, adapter.getSurfaceControl()); + ASSERT_EQ(mDisplayWidth, adapter.getWidth()); + ASSERT_EQ(mDisplayHeight, adapter.getHeight()); + ASSERT_EQ(nullptr, adapter.getNextTransaction()); +} + +TEST_F(BLASTBufferQueueTest, Update) { + BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); + sp<SurfaceControl> updateSurface = + mClient->createSurface(String8("UpdateTest"), mDisplayWidth / 2, mDisplayHeight / 2, + PIXEL_FORMAT_RGBA_8888); + adapter.update(updateSurface, mDisplayWidth / 2, mDisplayHeight / 2); + ASSERT_EQ(updateSurface, adapter.getSurfaceControl()); + ASSERT_EQ(mDisplayWidth / 2, adapter.getWidth()); + ASSERT_EQ(mDisplayHeight / 2, adapter.getHeight()); +} + +TEST_F(BLASTBufferQueueTest, SetNextTransaction) { + BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); + Transaction next; + adapter.setNextTransaction(&next); + ASSERT_EQ(&next, adapter.getNextTransaction()); +} + +TEST_F(BLASTBufferQueueTest, DISABLED_onFrameAvailable_ApplyDesiredPresentTime) { + BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); + sp<IGraphicBufferProducer> igbProducer; + setUpProducer(adapter, igbProducer); + + int slot; + sp<Fence> fence; + sp<GraphicBuffer> buf; + auto ret = igbProducer->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight, + PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN, + nullptr, nullptr); + ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret); + ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf)); + + nsecs_t desiredPresentTime = systemTime() + nsecs_t(5 * 1e8); + IGraphicBufferProducer::QueueBufferOutput qbOutput; + IGraphicBufferProducer::QueueBufferInput input(desiredPresentTime, false, HAL_DATASPACE_UNKNOWN, + Rect(mDisplayWidth, mDisplayHeight), + NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, + Fence::NO_FENCE); + igbProducer->queueBuffer(slot, input, &qbOutput); + ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint); + + adapter.waitForCallbacks(); + ASSERT_GE(systemTime(), desiredPresentTime); +} + +TEST_F(BLASTBufferQueueTest, onFrameAvailable_Apply) { + uint8_t r = 255; + uint8_t g = 0; + uint8_t b = 0; + + BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); + sp<IGraphicBufferProducer> igbProducer; + setUpProducer(adapter, igbProducer); + + int slot; + sp<Fence> fence; + sp<GraphicBuffer> buf; + auto ret = igbProducer->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight, + PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN, + nullptr, nullptr); + ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret); + ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf)); + + uint32_t* bufData; + buf->lock(static_cast<uint32_t>(GraphicBuffer::USAGE_SW_WRITE_OFTEN), + reinterpret_cast<void**>(&bufData)); + fillBuffer(bufData, Rect(buf->getWidth(), buf->getHeight()), buf->getStride(), r, g, b); + buf->unlock(); + + IGraphicBufferProducer::QueueBufferOutput qbOutput; + IGraphicBufferProducer::QueueBufferInput input(systemTime(), false, HAL_DATASPACE_UNKNOWN, + Rect(mDisplayWidth, mDisplayHeight), + NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, + Fence::NO_FENCE); + igbProducer->queueBuffer(slot, input, &qbOutput); + ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint); + + adapter.waitForCallbacks(); + + // capture screen and verify that it is red + bool capturedSecureLayers; + ASSERT_EQ(NO_ERROR, + mComposer->captureScreen(mDisplayToken, &mScreenCaptureBuf, capturedSecureLayers, + ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888, Rect(), + mDisplayWidth, mDisplayHeight, + /*useIdentityTransform*/ false)); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); +} + +TEST_F(BLASTBufferQueueTest, TripleBuffering) { + BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); + sp<IGraphicBufferProducer> igbProducer; + setUpProducer(adapter, igbProducer); + + std::vector<std::pair<int, sp<Fence>>> allocated; + for (int i = 0; i < 3; i++) { + int slot; + sp<Fence> fence; + sp<GraphicBuffer> buf; + auto ret = igbProducer->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight, + PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN, + nullptr, nullptr); + ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret); + ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf)); + allocated.push_back({slot, fence}); + } + for (int i = 0; i < allocated.size(); i++) { + igbProducer->cancelBuffer(allocated[i].first, allocated[i].second); + } + + for (int i = 0; i < 100; i++) { + int slot; + sp<Fence> fence; + sp<GraphicBuffer> buf; + auto ret = igbProducer->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight, + PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN, + nullptr, nullptr); + ASSERT_EQ(NO_ERROR, ret); + IGraphicBufferProducer::QueueBufferOutput qbOutput; + IGraphicBufferProducer::QueueBufferInput input(systemTime(), false, HAL_DATASPACE_UNKNOWN, + Rect(mDisplayWidth, mDisplayHeight), + NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, + Fence::NO_FENCE); + igbProducer->queueBuffer(slot, input, &qbOutput); + } + adapter.waitForCallbacks(); +} + +TEST_F(BLASTBufferQueueTest, SetCrop_Item) { + uint8_t r = 255; + uint8_t g = 0; + uint8_t b = 0; + + BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); + sp<IGraphicBufferProducer> igbProducer; + setUpProducer(adapter, igbProducer); + int slot; + sp<Fence> fence; + sp<GraphicBuffer> buf; + auto ret = igbProducer->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight, + PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN, + nullptr, nullptr); + ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret); + ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf)); + + uint32_t* bufData; + buf->lock(static_cast<uint32_t>(GraphicBuffer::USAGE_SW_WRITE_OFTEN), + reinterpret_cast<void**>(&bufData)); + fillBuffer(bufData, Rect(buf->getWidth(), buf->getHeight() / 2), buf->getStride(), r, g, b); + buf->unlock(); + + IGraphicBufferProducer::QueueBufferOutput qbOutput; + IGraphicBufferProducer::QueueBufferInput input(systemTime(), false, HAL_DATASPACE_UNKNOWN, + Rect(mDisplayWidth, mDisplayHeight / 2), + NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, + Fence::NO_FENCE); + igbProducer->queueBuffer(slot, input, &qbOutput); + ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint); + + adapter.waitForCallbacks(); + // capture screen and verify that it is red + bool capturedSecureLayers; + ASSERT_EQ(NO_ERROR, + mComposer->captureScreen(mDisplayToken, &mScreenCaptureBuf, capturedSecureLayers, + ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888, Rect(), + mDisplayWidth, mDisplayHeight, + /*useIdentityTransform*/ false)); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); +} + +TEST_F(BLASTBufferQueueTest, SetCrop_ScalingModeScaleCrop) { + uint8_t r = 255; + uint8_t g = 0; + uint8_t b = 0; + + int32_t bufferSideLength = + (mDisplayWidth < mDisplayHeight) ? mDisplayWidth / 2 : mDisplayHeight / 2; + int32_t finalCropSideLength = bufferSideLength / 2; + + auto bg = mClient->createSurface(String8("BGTest"), 0, 0, PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceEffect); + ASSERT_NE(nullptr, bg.get()); + Transaction t; + t.setLayerStack(bg, 0) + .setCrop_legacy(bg, Rect(0, 0, mDisplayWidth, mDisplayHeight)) + .setColor(bg, half3{0, 0, 0}) + .setLayer(bg, 0) + .apply(); + + BLASTBufferQueueHelper adapter(mSurfaceControl, bufferSideLength, bufferSideLength); + sp<IGraphicBufferProducer> igbProducer; + setUpProducer(adapter, igbProducer); + int slot; + sp<Fence> fence; + sp<GraphicBuffer> buf; + auto ret = igbProducer->dequeueBuffer(&slot, &fence, bufferSideLength, bufferSideLength, + PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN, + nullptr, nullptr); + ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret); + ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf)); + + uint32_t* bufData; + buf->lock(static_cast<uint32_t>(GraphicBuffer::USAGE_SW_WRITE_OFTEN), + reinterpret_cast<void**>(&bufData)); + fillBuffer(bufData, Rect(buf->getWidth(), buf->getHeight()), buf->getStride(), 0, 0, 0); + fillBuffer(bufData, + Rect(finalCropSideLength / 2, 0, buf->getWidth() - finalCropSideLength / 2, + buf->getHeight()), + buf->getStride(), r, g, b); + buf->unlock(); + + IGraphicBufferProducer::QueueBufferOutput qbOutput; + IGraphicBufferProducer::QueueBufferInput input(systemTime(), false, HAL_DATASPACE_UNKNOWN, + Rect(bufferSideLength, finalCropSideLength), + NATIVE_WINDOW_SCALING_MODE_SCALE_CROP, 0, + Fence::NO_FENCE); + igbProducer->queueBuffer(slot, input, &qbOutput); + ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint); + + adapter.waitForCallbacks(); + // capture screen and verify that it is red + bool capturedSecureLayers; + ASSERT_EQ(NO_ERROR, + mComposer->captureScreen(mDisplayToken, &mScreenCaptureBuf, capturedSecureLayers, + ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888, Rect(), + mDisplayWidth, mDisplayHeight, + /*useIdentityTransform*/ false)); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(r, g, b, + {0, 0, (int32_t)bufferSideLength, (int32_t)bufferSideLength})); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(0, 0, 0, + {0, 0, (int32_t)bufferSideLength, (int32_t)bufferSideLength}, + /*border*/ 0, /*outsideRegion*/ true)); +} + +class BLASTBufferQueueTransformTest : public BLASTBufferQueueTest { +public: + void test(uint32_t tr) { + BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); + sp<IGraphicBufferProducer> igbProducer; + setUpProducer(adapter, igbProducer); + + auto bufWidth = mDisplayWidth; + auto bufHeight = mDisplayHeight; + int slot; + sp<Fence> fence; + sp<GraphicBuffer> buf; + + auto ret = igbProducer->dequeueBuffer(&slot, &fence, bufWidth, bufHeight, + PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN, + nullptr, nullptr); + ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret); + ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf)); + + fillQuadrants(buf); + + IGraphicBufferProducer::QueueBufferOutput qbOutput; + IGraphicBufferProducer::QueueBufferInput input(systemTime(), false, HAL_DATASPACE_UNKNOWN, + Rect(bufWidth, bufHeight), + NATIVE_WINDOW_SCALING_MODE_FREEZE, tr, + Fence::NO_FENCE); + igbProducer->queueBuffer(slot, input, &qbOutput); + ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint); + + adapter.waitForCallbacks(); + bool capturedSecureLayers; + ASSERT_EQ(NO_ERROR, + mComposer->captureScreen(mDisplayToken, &mScreenCaptureBuf, capturedSecureLayers, + ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888, + Rect(), mDisplayWidth, mDisplayHeight, + /*useIdentityTransform*/ false)); + switch (tr) { + case ui::Transform::ROT_0: + ASSERT_NO_FATAL_FAILURE(checkScreenCapture(0, 0, 0, + {0, 0, (int32_t)mDisplayWidth / 2, + (int32_t)mDisplayHeight / 2}, + 1)); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(255, 0, 0, + {(int32_t)mDisplayWidth / 2, 0, (int32_t)mDisplayWidth, + (int32_t)mDisplayHeight / 2}, + 1)); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(0, 255, 0, + {(int32_t)mDisplayWidth / 2, (int32_t)mDisplayHeight / 2, + (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}, + 1)); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(0, 0, 255, + {0, (int32_t)mDisplayHeight / 2, + (int32_t)mDisplayWidth / 2, (int32_t)mDisplayHeight}, + 1)); + break; + case ui::Transform::FLIP_H: + ASSERT_NO_FATAL_FAILURE(checkScreenCapture(255, 0, 0, + {0, 0, (int32_t)mDisplayWidth / 2, + (int32_t)mDisplayHeight / 2}, + 1)); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(0, 0, 0, + {(int32_t)mDisplayWidth / 2, 0, (int32_t)mDisplayWidth, + (int32_t)mDisplayHeight / 2}, + 1)); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(0, 0, 255, + {(int32_t)mDisplayWidth / 2, (int32_t)mDisplayHeight / 2, + (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}, + 1)); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(0, 255, 0, + {0, (int32_t)mDisplayHeight / 2, + (int32_t)mDisplayWidth / 2, (int32_t)mDisplayHeight}, + 1)); + break; + case ui::Transform::FLIP_V: + ASSERT_NO_FATAL_FAILURE(checkScreenCapture(0, 0, 255, + {0, 0, (int32_t)mDisplayWidth / 2, + (int32_t)mDisplayHeight / 2}, + 1)); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(0, 255, 0, + {(int32_t)mDisplayWidth / 2, 0, (int32_t)mDisplayWidth, + (int32_t)mDisplayHeight / 2}, + 1)); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(255, 0, 0, + {(int32_t)mDisplayWidth / 2, (int32_t)mDisplayHeight / 2, + (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}, + 1)); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(0, 0, 0, + {0, (int32_t)mDisplayHeight / 2, + (int32_t)mDisplayWidth / 2, (int32_t)mDisplayHeight}, + 1)); + break; + case ui::Transform::ROT_90: + ASSERT_NO_FATAL_FAILURE(checkScreenCapture(0, 0, 255, + {0, 0, (int32_t)mDisplayWidth / 2, + (int32_t)mDisplayHeight / 2}, + 1)); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(0, 0, 0, + {(int32_t)mDisplayWidth / 2, 0, (int32_t)mDisplayWidth, + (int32_t)mDisplayHeight / 2}, + 1)); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(255, 0, 0, + {(int32_t)mDisplayWidth / 2, (int32_t)mDisplayHeight / 2, + (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}, + 1)); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(0, 255, 0, + {0, (int32_t)mDisplayHeight / 2, + (int32_t)mDisplayWidth / 2, (int32_t)mDisplayHeight}, + 1)); + break; + case ui::Transform::ROT_180: + ASSERT_NO_FATAL_FAILURE(checkScreenCapture(0, 255, 0, + {0, 0, (int32_t)mDisplayWidth / 2, + (int32_t)mDisplayHeight / 2}, + 1)); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(0, 0, 255, + {(int32_t)mDisplayWidth / 2, 0, (int32_t)mDisplayWidth, + (int32_t)mDisplayHeight / 2}, + 1)); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(0, 0, 0, + {(int32_t)mDisplayWidth / 2, (int32_t)mDisplayHeight / 2, + (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}, + 1)); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(255, 0, 0, + {0, (int32_t)mDisplayHeight / 2, + (int32_t)mDisplayWidth / 2, (int32_t)mDisplayHeight}, + 1)); + break; + case ui::Transform::ROT_270: + ASSERT_NO_FATAL_FAILURE(checkScreenCapture(255, 0, 0, + {0, 0, (int32_t)mDisplayWidth / 2, + (int32_t)mDisplayHeight / 2}, + 1)); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(0, 255, 0, + {(int32_t)mDisplayWidth / 2, 0, (int32_t)mDisplayWidth, + (int32_t)mDisplayHeight / 2}, + 1)); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(0, 0, 255, + {(int32_t)mDisplayWidth / 2, (int32_t)mDisplayHeight / 2, + (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}, + 1)); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(0, 0, 0, + {0, (int32_t)mDisplayHeight / 2, + (int32_t)mDisplayWidth / 2, (int32_t)mDisplayHeight}, + 1)); + } + } +}; + +TEST_F(BLASTBufferQueueTransformTest, setTransform_ROT_0) { + test(ui::Transform::ROT_0); +} + +TEST_F(BLASTBufferQueueTransformTest, setTransform_FLIP_H) { + test(ui::Transform::FLIP_H); +} + +TEST_F(BLASTBufferQueueTransformTest, setTransform_FLIP_V) { + test(ui::Transform::FLIP_V); +} + +TEST_F(BLASTBufferQueueTransformTest, setTransform_ROT_90) { + test(ui::Transform::ROT_90); +} + +TEST_F(BLASTBufferQueueTransformTest, setTransform_ROT_180) { + test(ui::Transform::ROT_180); +} + +TEST_F(BLASTBufferQueueTransformTest, setTransform_ROT_270) { + test(ui::Transform::ROT_270); +} + +class BLASTFrameEventHistoryTest : public BLASTBufferQueueTest { +public: + void setUpAndQueueBuffer(const sp<IGraphicBufferProducer>& igbProducer, + nsecs_t* requestedPresentTime, nsecs_t* postedTime, + IGraphicBufferProducer::QueueBufferOutput* qbOutput, + bool getFrameTimestamps) { + int slot; + sp<Fence> fence; + sp<GraphicBuffer> buf; + auto ret = igbProducer->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight, + PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN, + nullptr, nullptr); + ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret); + ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf)); + + nsecs_t requestedTime = systemTime(); + if (requestedPresentTime) *requestedPresentTime = requestedTime; + IGraphicBufferProducer::QueueBufferInput input(requestedTime, false, HAL_DATASPACE_UNKNOWN, + Rect(mDisplayWidth, mDisplayHeight), + NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, + Fence::NO_FENCE, /*sticky*/ 0, + getFrameTimestamps); + if (postedTime) *postedTime = systemTime(); + igbProducer->queueBuffer(slot, input, qbOutput); + } +}; + +TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_Basic) { + BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); + sp<IGraphicBufferProducer> igbProducer; + ProducerFrameEventHistory history; + setUpProducer(adapter, igbProducer); + + IGraphicBufferProducer::QueueBufferOutput qbOutput; + nsecs_t requestedPresentTimeA = 0; + nsecs_t postedTimeA = 0; + setUpAndQueueBuffer(igbProducer, &requestedPresentTimeA, &postedTimeA, &qbOutput, true); + history.applyDelta(qbOutput.frameTimestamps); + + FrameEvents* events = nullptr; + events = history.getFrame(1); + ASSERT_NE(nullptr, events); + ASSERT_EQ(1, events->frameNumber); + ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime); + ASSERT_GE(events->postedTime, postedTimeA); + + adapter.waitForCallbacks(); + + // queue another buffer so we query for frame event deltas + nsecs_t requestedPresentTimeB = 0; + nsecs_t postedTimeB = 0; + setUpAndQueueBuffer(igbProducer, &requestedPresentTimeB, &postedTimeB, &qbOutput, true); + history.applyDelta(qbOutput.frameTimestamps); + events = history.getFrame(1); + ASSERT_NE(nullptr, events); + + // frame number, requestedPresentTime, and postTime should not have changed + ASSERT_EQ(1, events->frameNumber); + ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime); + ASSERT_GE(events->postedTime, postedTimeA); + + ASSERT_GE(events->latchTime, postedTimeA); + ASSERT_GE(events->dequeueReadyTime, events->latchTime); + ASSERT_NE(nullptr, events->gpuCompositionDoneFence); + ASSERT_NE(nullptr, events->displayPresentFence); + ASSERT_NE(nullptr, events->releaseFence); + + // we should also have gotten the initial values for the next frame + events = history.getFrame(2); + ASSERT_NE(nullptr, events); + ASSERT_EQ(2, events->frameNumber); + ASSERT_EQ(requestedPresentTimeB, events->requestedPresentTime); + ASSERT_GE(events->postedTime, postedTimeB); + + // wait for any callbacks that have not been received + adapter.waitForCallbacks(); +} +} // namespace android diff --git a/libs/gui/tests/BufferItemConsumer_test.cpp b/libs/gui/tests/BufferItemConsumer_test.cpp index b87cbbdec8..fc6551c8e6 100644 --- a/libs/gui/tests/BufferItemConsumer_test.cpp +++ b/libs/gui/tests/BufferItemConsumer_test.cpp @@ -51,7 +51,7 @@ class BufferItemConsumerTest : public ::testing::Test { mBFL = new BufferFreedListener(this); mBIC->setBufferFreedListener(mBFL); - sp<IProducerListener> producerListener = new DummyProducerListener(); + sp<IProducerListener> producerListener = new StubProducerListener(); IGraphicBufferProducer::QueueBufferOutput bufferOutput; ASSERT_EQ(NO_ERROR, mProducer->connect(producerListener, NATIVE_WINDOW_API_CPU, @@ -131,7 +131,7 @@ class BufferItemConsumerTest : public ::testing::Test { // Test that detaching buffer from consumer side triggers onBufferFreed. TEST_F(BufferItemConsumerTest, TriggerBufferFreed_DetachBufferFromConsumer) { int slot; - // Producer: generate a dummy buffer. + // Producer: generate a placeholder buffer. DequeueBuffer(&slot); QueueBuffer(slot); diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index 406f21faf6..d1208ee5ae 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -17,7 +17,7 @@ #define LOG_TAG "BufferQueue_test" //#define LOG_NDEBUG 0 -#include "DummyConsumer.h" +#include "MockConsumer.h" #include <gui/BufferItem.h> #include <gui/BufferQueue.h> @@ -134,8 +134,8 @@ TEST_F(BufferQueueTest, DISABLED_BufferQueueInAnotherProcess) { mConsumer = interface_cast<IGraphicBufferConsumer>(binderConsumer); EXPECT_TRUE(mConsumer != nullptr); - sp<DummyConsumer> dc(new DummyConsumer); - ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false)); + sp<MockConsumer> mc(new MockConsumer); + ASSERT_EQ(OK, mConsumer->consumerConnect(mc, false)); IGraphicBufferProducer::QueueBufferOutput output; ASSERT_EQ(OK, mProducer->connect(nullptr, NATIVE_WINDOW_API_CPU, false, &output)); @@ -169,13 +169,24 @@ TEST_F(BufferQueueTest, DISABLED_BufferQueueInAnotherProcess) { ASSERT_EQ(OK, item.mGraphicBuffer->unlock()); } +TEST_F(BufferQueueTest, GetMaxBufferCountInQueueBufferOutput_Succeeds) { + createBufferQueue(); + sp<MockConsumer> mc(new MockConsumer); + mConsumer->consumerConnect(mc, false); + int bufferCount = 50; + mConsumer->setMaxBufferCount(bufferCount); + + IGraphicBufferProducer::QueueBufferOutput output; + mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false, &output); + ASSERT_EQ(output.maxBufferCount, bufferCount); +} + TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) { createBufferQueue(); - sp<DummyConsumer> dc(new DummyConsumer); - mConsumer->consumerConnect(dc, false); + sp<MockConsumer> mc(new MockConsumer); + mConsumer->consumerConnect(mc, false); IGraphicBufferProducer::QueueBufferOutput qbo; - mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false, - &qbo); + mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false, &qbo); mProducer->setMaxDequeuedBufferCount(3); int slot; @@ -207,15 +218,14 @@ TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) { TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithIllegalValues_ReturnsError) { createBufferQueue(); - sp<DummyConsumer> dc(new DummyConsumer); - mConsumer->consumerConnect(dc, false); + sp<MockConsumer> mc(new MockConsumer); + mConsumer->consumerConnect(mc, false); EXPECT_EQ(OK, mConsumer->setMaxBufferCount(10)); EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount(10)); IGraphicBufferProducer::QueueBufferOutput qbo; - mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false, - &qbo); + mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false, &qbo); mProducer->setMaxDequeuedBufferCount(3); int minBufferCount; @@ -251,12 +261,11 @@ TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithIllegalValues_ReturnsError) TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithLegalValues_Succeeds) { createBufferQueue(); - sp<DummyConsumer> dc(new DummyConsumer); - mConsumer->consumerConnect(dc, false); + sp<MockConsumer> mc(new MockConsumer); + mConsumer->consumerConnect(mc, false); IGraphicBufferProducer::QueueBufferOutput qbo; - mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false, - &qbo); + mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false, &qbo); mProducer->setMaxDequeuedBufferCount(2); int minBufferCount; @@ -298,8 +307,8 @@ TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithLegalValues_Succeeds) { TEST_F(BufferQueueTest, SetMaxBufferCountWithLegalValues_Succeeds) { createBufferQueue(); - sp<DummyConsumer> dc(new DummyConsumer); - mConsumer->consumerConnect(dc, false); + sp<MockConsumer> mc(new MockConsumer); + mConsumer->consumerConnect(mc, false); // Test shared buffer mode EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(1)); @@ -307,8 +316,8 @@ TEST_F(BufferQueueTest, SetMaxBufferCountWithLegalValues_Succeeds) { TEST_F(BufferQueueTest, SetMaxBufferCountWithIllegalValues_ReturnsError) { createBufferQueue(); - sp<DummyConsumer> dc(new DummyConsumer); - mConsumer->consumerConnect(dc, false); + sp<MockConsumer> mc(new MockConsumer); + mConsumer->consumerConnect(mc, false); EXPECT_EQ(BAD_VALUE, mConsumer->setMaxBufferCount(0)); EXPECT_EQ(BAD_VALUE, mConsumer->setMaxBufferCount( @@ -320,11 +329,11 @@ TEST_F(BufferQueueTest, SetMaxBufferCountWithIllegalValues_ReturnsError) { TEST_F(BufferQueueTest, DetachAndReattachOnProducerSide) { createBufferQueue(); - sp<DummyConsumer> dc(new DummyConsumer); - ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false)); + sp<MockConsumer> mc(new MockConsumer); + ASSERT_EQ(OK, mConsumer->consumerConnect(mc, false)); IGraphicBufferProducer::QueueBufferOutput output; - ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, - NATIVE_WINDOW_API_CPU, false, &output)); + ASSERT_EQ(OK, + mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false, &output)); ASSERT_EQ(BAD_VALUE, mProducer->detachBuffer(-1)); // Index too low ASSERT_EQ(BAD_VALUE, mProducer->detachBuffer( @@ -374,11 +383,11 @@ TEST_F(BufferQueueTest, DetachAndReattachOnProducerSide) { TEST_F(BufferQueueTest, DetachAndReattachOnConsumerSide) { createBufferQueue(); - sp<DummyConsumer> dc(new DummyConsumer); - ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false)); + sp<MockConsumer> mc(new MockConsumer); + ASSERT_EQ(OK, mConsumer->consumerConnect(mc, false)); IGraphicBufferProducer::QueueBufferOutput output; - ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, - NATIVE_WINDOW_API_CPU, false, &output)); + ASSERT_EQ(OK, + mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false, &output)); int slot; sp<Fence> fence; @@ -433,11 +442,11 @@ TEST_F(BufferQueueTest, DetachAndReattachOnConsumerSide) { TEST_F(BufferQueueTest, MoveFromConsumerToProducer) { createBufferQueue(); - sp<DummyConsumer> dc(new DummyConsumer); - ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false)); + sp<MockConsumer> mc(new MockConsumer); + ASSERT_EQ(OK, mConsumer->consumerConnect(mc, false)); IGraphicBufferProducer::QueueBufferOutput output; - ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, - NATIVE_WINDOW_API_CPU, false, &output)); + ASSERT_EQ(OK, + mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false, &output)); int slot; sp<Fence> fence; @@ -476,11 +485,11 @@ TEST_F(BufferQueueTest, MoveFromConsumerToProducer) { TEST_F(BufferQueueTest, TestDisallowingAllocation) { createBufferQueue(); - sp<DummyConsumer> dc(new DummyConsumer); - ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true)); + sp<MockConsumer> mc(new MockConsumer); + ASSERT_EQ(OK, mConsumer->consumerConnect(mc, true)); IGraphicBufferProducer::QueueBufferOutput output; - ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, - NATIVE_WINDOW_API_CPU, true, &output)); + ASSERT_EQ(OK, + mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, true, &output)); static const uint32_t WIDTH = 320; static const uint32_t HEIGHT = 240; @@ -514,11 +523,11 @@ TEST_F(BufferQueueTest, TestDisallowingAllocation) { TEST_F(BufferQueueTest, TestGenerationNumbers) { createBufferQueue(); - sp<DummyConsumer> dc(new DummyConsumer); - ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true)); + sp<MockConsumer> mc(new MockConsumer); + ASSERT_EQ(OK, mConsumer->consumerConnect(mc, true)); IGraphicBufferProducer::QueueBufferOutput output; - ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, - NATIVE_WINDOW_API_CPU, true, &output)); + ASSERT_EQ(OK, + mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, true, &output)); ASSERT_EQ(OK, mProducer->setGenerationNumber(1)); @@ -556,11 +565,11 @@ TEST_F(BufferQueueTest, TestGenerationNumbers) { TEST_F(BufferQueueTest, TestSharedBufferModeWithoutAutoRefresh) { createBufferQueue(); - sp<DummyConsumer> dc(new DummyConsumer); - ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true)); + sp<MockConsumer> mc(new MockConsumer); + ASSERT_EQ(OK, mConsumer->consumerConnect(mc, true)); IGraphicBufferProducer::QueueBufferOutput output; - ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, - NATIVE_WINDOW_API_CPU, true, &output)); + ASSERT_EQ(OK, + mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, true, &output)); ASSERT_EQ(OK, mProducer->setSharedBufferMode(true)); @@ -606,11 +615,11 @@ TEST_F(BufferQueueTest, TestSharedBufferModeWithoutAutoRefresh) { TEST_F(BufferQueueTest, TestSharedBufferModeWithAutoRefresh) { createBufferQueue(); - sp<DummyConsumer> dc(new DummyConsumer); - ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true)); + sp<MockConsumer> mc(new MockConsumer); + ASSERT_EQ(OK, mConsumer->consumerConnect(mc, true)); IGraphicBufferProducer::QueueBufferOutput output; - ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, - NATIVE_WINDOW_API_CPU, true, &output)); + ASSERT_EQ(OK, + mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, true, &output)); ASSERT_EQ(OK, mProducer->setSharedBufferMode(true)); ASSERT_EQ(OK, mProducer->setAutoRefresh(true)); @@ -675,11 +684,11 @@ TEST_F(BufferQueueTest, TestSharedBufferModeWithAutoRefresh) { TEST_F(BufferQueueTest, TestSharedBufferModeUsingAlreadyDequeuedBuffer) { createBufferQueue(); - sp<DummyConsumer> dc(new DummyConsumer); - ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true)); + sp<MockConsumer> mc(new MockConsumer); + ASSERT_EQ(OK, mConsumer->consumerConnect(mc, true)); IGraphicBufferProducer::QueueBufferOutput output; - ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, - NATIVE_WINDOW_API_CPU, true, &output)); + ASSERT_EQ(OK, + mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, true, &output)); // Dequeue a buffer int sharedSlot; @@ -726,11 +735,11 @@ TEST_F(BufferQueueTest, TestSharedBufferModeUsingAlreadyDequeuedBuffer) { TEST_F(BufferQueueTest, TestTimeouts) { createBufferQueue(); - sp<DummyConsumer> dc(new DummyConsumer); - ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true)); + sp<MockConsumer> mc(new MockConsumer); + ASSERT_EQ(OK, mConsumer->consumerConnect(mc, true)); IGraphicBufferProducer::QueueBufferOutput output; - ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, - NATIVE_WINDOW_API_CPU, true, &output)); + ASSERT_EQ(OK, + mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, true, &output)); // Fill up the queue. Since the controlledByApp flags are set to true, this // queue should be in non-blocking mode, and we should be recycling the same @@ -788,11 +797,11 @@ TEST_F(BufferQueueTest, TestTimeouts) { TEST_F(BufferQueueTest, CanAttachWhileDisallowingAllocation) { createBufferQueue(); - sp<DummyConsumer> dc(new DummyConsumer); - ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true)); + sp<MockConsumer> mc(new MockConsumer); + ASSERT_EQ(OK, mConsumer->consumerConnect(mc, true)); IGraphicBufferProducer::QueueBufferOutput output; - ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, - NATIVE_WINDOW_API_CPU, true, &output)); + ASSERT_EQ(OK, + mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, true, &output)); int slot = BufferQueue::INVALID_BUFFER_SLOT; sp<Fence> sourceFence; @@ -810,11 +819,11 @@ TEST_F(BufferQueueTest, CanAttachWhileDisallowingAllocation) { TEST_F(BufferQueueTest, CanRetrieveLastQueuedBuffer) { createBufferQueue(); - sp<DummyConsumer> dc(new DummyConsumer); - ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false)); + sp<MockConsumer> mc(new MockConsumer); + ASSERT_EQ(OK, mConsumer->consumerConnect(mc, false)); IGraphicBufferProducer::QueueBufferOutput output; - ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, - NATIVE_WINDOW_API_CPU, false, &output)); + ASSERT_EQ(OK, + mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false, &output)); // Dequeue and queue the first buffer, storing the handle int slot = BufferQueue::INVALID_BUFFER_SLOT; @@ -864,11 +873,11 @@ TEST_F(BufferQueueTest, CanRetrieveLastQueuedBuffer) { TEST_F(BufferQueueTest, TestOccupancyHistory) { createBufferQueue(); - sp<DummyConsumer> dc(new DummyConsumer); - ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false)); + sp<MockConsumer> mc(new MockConsumer); + ASSERT_EQ(OK, mConsumer->consumerConnect(mc, false)); IGraphicBufferProducer::QueueBufferOutput output; - ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, - NATIVE_WINDOW_API_CPU, false, &output)); + ASSERT_EQ(OK, + mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false, &output)); int slot = BufferQueue::INVALID_BUFFER_SLOT; sp<Fence> fence = Fence::NO_FENCE; @@ -1018,8 +1027,8 @@ private: TEST_F(BufferQueueTest, TestDiscardFreeBuffers) { createBufferQueue(); - sp<DummyConsumer> dc(new DummyConsumer); - ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false)); + sp<MockConsumer> mc(new MockConsumer); + ASSERT_EQ(OK, mConsumer->consumerConnect(mc, false)); IGraphicBufferProducer::QueueBufferOutput output; sp<BufferDiscardedListener> pl(new BufferDiscardedListener); ASSERT_EQ(OK, mProducer->connect(pl, @@ -1103,11 +1112,11 @@ TEST_F(BufferQueueTest, TestDiscardFreeBuffers) { TEST_F(BufferQueueTest, TestBufferReplacedInQueueBuffer) { createBufferQueue(); - sp<DummyConsumer> dc(new DummyConsumer); - ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true)); + sp<MockConsumer> mc(new MockConsumer); + ASSERT_EQ(OK, mConsumer->consumerConnect(mc, true)); IGraphicBufferProducer::QueueBufferOutput output; - ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, - NATIVE_WINDOW_API_CPU, true, &output)); + ASSERT_EQ(OK, + mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, true, &output)); ASSERT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(1)); int slot = BufferQueue::INVALID_BUFFER_SLOT; @@ -1144,12 +1153,11 @@ TEST_F(BufferQueueTest, TestBufferReplacedInQueueBuffer) { TEST_F(BufferQueueTest, TestStaleBufferHandleSentAfterDisconnect) { createBufferQueue(); - sp<DummyConsumer> dc(new DummyConsumer); - ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true)); + sp<MockConsumer> mc(new MockConsumer); + ASSERT_EQ(OK, mConsumer->consumerConnect(mc, true)); IGraphicBufferProducer::QueueBufferOutput output; - sp<IProducerListener> dummyListener(new DummyProducerListener); - ASSERT_EQ(OK, mProducer->connect(dummyListener, NATIVE_WINDOW_API_CPU, - true, &output)); + sp<IProducerListener> fakeListener(new StubProducerListener); + ASSERT_EQ(OK, mProducer->connect(fakeListener, NATIVE_WINDOW_API_CPU, true, &output)); int slot = BufferQueue::INVALID_BUFFER_SLOT; sp<Fence> fence = Fence::NO_FENCE; @@ -1203,15 +1211,13 @@ TEST_F(BufferQueueTest, TestStaleBufferHandleSentAfterDisconnect) { TEST_F(BufferQueueTest, TestProducerConnectDisconnect) { createBufferQueue(); - sp<DummyConsumer> dc(new DummyConsumer); - ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true)); + sp<MockConsumer> mc(new MockConsumer); + ASSERT_EQ(OK, mConsumer->consumerConnect(mc, true)); IGraphicBufferProducer::QueueBufferOutput output; - sp<IProducerListener> dummyListener(new DummyProducerListener); + sp<IProducerListener> fakeListener(new StubProducerListener); ASSERT_EQ(NO_INIT, mProducer->disconnect(NATIVE_WINDOW_API_CPU)); - ASSERT_EQ(OK, mProducer->connect( - dummyListener, NATIVE_WINDOW_API_CPU, true, &output)); - ASSERT_EQ(BAD_VALUE, mProducer->connect( - dummyListener, NATIVE_WINDOW_API_MEDIA, true, &output)); + ASSERT_EQ(OK, mProducer->connect(fakeListener, NATIVE_WINDOW_API_CPU, true, &output)); + ASSERT_EQ(BAD_VALUE, mProducer->connect(fakeListener, NATIVE_WINDOW_API_MEDIA, true, &output)); ASSERT_EQ(BAD_VALUE, mProducer->disconnect(NATIVE_WINDOW_API_MEDIA)); ASSERT_EQ(OK, mProducer->disconnect(NATIVE_WINDOW_API_CPU)); diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index 03b9cd75db..b1d3ecbf36 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -41,7 +41,7 @@ #include <input/InputTransport.h> #include <input/Input.h> -#include <ui/DisplayInfo.h> +#include <ui/DisplayConfig.h> #include <ui/Rect.h> #include <ui/Region.h> @@ -69,7 +69,6 @@ public: mSurfaceControl = sc; InputChannel::openInputChannelPair("testchannels", mServerChannel, mClientChannel); - mServerChannel->setToken(new BBinder()); mInputFlinger = getInputFlinger(); mInputFlinger->registerInputChannel(mServerChannel); @@ -83,7 +82,8 @@ public: int width, int height) { sp<SurfaceControl> surfaceControl = scc->createSurface(String8("Test Surface"), 0 /* bufHeight */, 0 /* bufWidth */, - PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor); + PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceEffect); return std::make_unique<InputSurface>(surfaceControl, width, height); } @@ -104,6 +104,15 @@ public: return std::make_unique<InputSurface>(surfaceControl, width, height); } + static std::unique_ptr<InputSurface> makeCursorInputSurface( + const sp<SurfaceComposerClient> &scc, int width, int height) { + sp<SurfaceControl> surfaceControl = + scc->createSurface(String8("Test Cursor Surface"), 0 /* bufHeight */, + 0 /* bufWidth */, PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eCursorWindow); + return std::make_unique<InputSurface>(surfaceControl, width, height); + } + InputEvent* consumeEvent() { waitForEventAvailable(); @@ -113,24 +122,35 @@ public: if (consumed != OK) { return nullptr; } - mInputConsumer->sendFinishedSignal(seqId, true); + status_t status = mInputConsumer->sendFinishedSignal(seqId, true); + EXPECT_EQ(OK, status) << "Could not send finished signal"; return ev; } + void assertFocusChange(bool hasFocus) { + InputEvent *ev = consumeEvent(); + ASSERT_NE(ev, nullptr); + ASSERT_EQ(AINPUT_EVENT_TYPE_FOCUS, ev->getType()); + FocusEvent *focusEvent = static_cast<FocusEvent *>(ev); + EXPECT_EQ(hasFocus, focusEvent->getHasFocus()); + } + void expectTap(int x, int y) { InputEvent* ev = consumeEvent(); - EXPECT_TRUE(ev != nullptr); - EXPECT_TRUE(ev->getType() == AINPUT_EVENT_TYPE_MOTION); + ASSERT_NE(ev, nullptr); + ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, ev->getType()); MotionEvent* mev = static_cast<MotionEvent*>(ev); EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, mev->getAction()); EXPECT_EQ(x, mev->getX(0)); EXPECT_EQ(y, mev->getY(0)); + EXPECT_EQ(0, mev->getFlags() & VERIFIED_MOTION_EVENT_FLAGS); ev = consumeEvent(); - EXPECT_TRUE(ev != nullptr); - EXPECT_TRUE(ev->getType() == AINPUT_EVENT_TYPE_MOTION); + ASSERT_NE(ev, nullptr); + ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, ev->getType()); mev = static_cast<MotionEvent*>(ev); EXPECT_EQ(AMOTION_EVENT_ACTION_UP, mev->getAction()); + EXPECT_EQ(0, mev->getFlags() & VERIFIED_MOTION_EVENT_FLAGS); } ~InputSurface() { @@ -165,11 +185,11 @@ private: } void populateInputInfo(int width, int height) { - mInputInfo.token = mServerChannel->getToken(); + mInputInfo.token = mServerChannel->getConnectionToken(); mInputInfo.name = "Test info"; mInputInfo.layoutParamsFlags = InputWindowInfo::FLAG_NOT_TOUCH_MODAL; mInputInfo.layoutParamsType = InputWindowInfo::TYPE_BASE_APPLICATION; - mInputInfo.dispatchingTimeout = 100000; + mInputInfo.dispatchingTimeout = seconds_to_nanoseconds(5); mInputInfo.globalScaleFactor = 1.0; mInputInfo.canReceiveKeys = true; mInputInfo.hasFocus = true; @@ -187,7 +207,7 @@ private: InputApplicationInfo aInfo; aInfo.token = new BBinder(); aInfo.name = "Test app info"; - aInfo.dispatchingTimeout = 100000; + aInfo.dispatchingTimeout = seconds_to_nanoseconds(5); mInputInfo.applicationInfo = aInfo; } @@ -213,15 +233,15 @@ public: ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); const auto display = mComposerClient->getInternalDisplayToken(); - ASSERT_FALSE(display == nullptr); + ASSERT_NE(display, nullptr); - DisplayInfo info; - ASSERT_EQ(NO_ERROR, mComposerClient->getDisplayInfo(display, &info)); + DisplayConfig config; + ASSERT_EQ(NO_ERROR, mComposerClient->getActiveDisplayConfig(display, &config)); // After a new buffer is queued, SurfaceFlinger is notified and will // latch the new buffer on next vsync. Let's heuristically wait for 3 // vsyncs. - mBufferPostDelay = int32_t(1e6 / info.fps) * 3; + mBufferPostDelay = static_cast<int32_t>(1e6 / config.refreshRate) * 3; } void TearDown() { @@ -260,18 +280,28 @@ void injectTap(int x, int y) { TEST_F(InputSurfacesTest, can_receive_input) { std::unique_ptr<InputSurface> surface = makeSurface(100, 100); surface->showAt(100, 100); + surface->assertFocusChange(true); injectTap(101, 101); - EXPECT_TRUE(surface->consumeEvent() != nullptr); + EXPECT_NE(surface->consumeEvent(), nullptr); } +/** + * Set up two surfaces side-by-side. Tap each surface. + * Next, swap the positions of the two surfaces. Inject tap into the two + * original locations. Ensure that the tap is received by the surfaces in the + * reverse order. + */ TEST_F(InputSurfacesTest, input_respects_positioning) { std::unique_ptr<InputSurface> surface = makeSurface(100, 100); surface->showAt(100, 100); + surface->assertFocusChange(true); std::unique_ptr<InputSurface> surface2 = makeSurface(100, 100); surface2->showAt(200, 200); + surface->assertFocusChange(false); + surface2->assertFocusChange(true); injectTap(201, 201); surface2->expectTap(1, 1); @@ -298,11 +328,16 @@ TEST_F(InputSurfacesTest, input_respects_layering) { std::unique_ptr<InputSurface> surface2 = makeSurface(100, 100); surface->showAt(10, 10); + surface->assertFocusChange(true); surface2->showAt(10, 10); + surface->assertFocusChange(false); + surface2->assertFocusChange(true); surface->doTransaction([](auto &t, auto &sc) { t.setLayer(sc, LAYER_BASE + 1); }); + surface2->assertFocusChange(false); + surface->assertFocusChange(true); injectTap(11, 11); surface->expectTap(1, 1); @@ -310,6 +345,8 @@ TEST_F(InputSurfacesTest, input_respects_layering) { surface2->doTransaction([](auto &t, auto &sc) { t.setLayer(sc, LAYER_BASE + 1); }); + surface2->assertFocusChange(true); + surface->assertFocusChange(false); injectTap(11, 11); surface2->expectTap(1, 1); @@ -317,6 +354,8 @@ TEST_F(InputSurfacesTest, input_respects_layering) { surface2->doTransaction([](auto &t, auto &sc) { t.hide(sc); }); + surface2->assertFocusChange(false); + surface->assertFocusChange(true); injectTap(11, 11); surface->expectTap(1, 1); @@ -329,9 +368,12 @@ TEST_F(InputSurfacesTest, input_respects_surface_insets) { std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100); std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100); bgSurface->showAt(100, 100); + bgSurface->assertFocusChange(true); fgSurface->mInputInfo.surfaceInset = 5; fgSurface->showAt(100, 100); + fgSurface->assertFocusChange(true); + bgSurface->assertFocusChange(false); injectTap(106, 106); fgSurface->expectTap(1, 1); @@ -345,9 +387,12 @@ TEST_F(InputSurfacesTest, input_respects_cropped_surface_insets) { std::unique_ptr<InputSurface> parentSurface = makeSurface(100, 100); std::unique_ptr<InputSurface> childSurface = makeSurface(100, 100); parentSurface->showAt(100, 100); + parentSurface->assertFocusChange(true); childSurface->mInputInfo.surfaceInset = 10; childSurface->showAt(100, 100); + childSurface->assertFocusChange(true); + parentSurface->assertFocusChange(false); childSurface->doTransaction([&](auto &t, auto &sc) { t.setPosition(sc, -5, -5); @@ -366,9 +411,12 @@ TEST_F(InputSurfacesTest, input_respects_scaled_surface_insets) { std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100); std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100); bgSurface->showAt(100, 100); + bgSurface->assertFocusChange(true); fgSurface->mInputInfo.surfaceInset = 5; fgSurface->showAt(100, 100); + bgSurface->assertFocusChange(false); + fgSurface->assertFocusChange(true); fgSurface->doTransaction([&](auto &t, auto &sc) { t.setMatrix(sc, 2.0, 0, 0, 4.0); }); @@ -385,6 +433,7 @@ TEST_F(InputSurfacesTest, input_respects_scaled_surface_insets_overflow) { // In case we pass the very big inset without any checking. fgSurface->mInputInfo.surfaceInset = INT32_MAX; fgSurface->showAt(100, 100); + fgSurface->assertFocusChange(true); fgSurface->doTransaction([&](auto &t, auto &sc) { t.setMatrix(sc, 2.0, 0, 0, 2.0); }); @@ -401,6 +450,7 @@ TEST_F(InputSurfacesTest, input_ignores_transparent_region) { t.setTransparentRegionHint(sc, transparentRegion); }); surface->showAt(100, 100); + surface->assertFocusChange(true); injectTap(101, 101); surface->expectTap(1, 1); } @@ -415,7 +465,10 @@ TEST_F(InputSurfacesTest, input_ignores_buffer_layer_buffer) { InputSurface::makeBufferInputSurface(mComposerClient, 100, 100); bgSurface->showAt(10, 10); + bgSurface->assertFocusChange(true); bufferSurface->showAt(10, 10); + bgSurface->assertFocusChange(false); + bufferSurface->assertFocusChange(true); injectTap(11, 11); bufferSurface->expectTap(1, 1); @@ -432,7 +485,10 @@ TEST_F(InputSurfacesTest, input_ignores_buffer_layer_alpha) { postBuffer(bufferSurface->mSurfaceControl); bgSurface->showAt(10, 10); + bgSurface->assertFocusChange(true); bufferSurface->showAt(10, 10); + bufferSurface->assertFocusChange(true); + bgSurface->assertFocusChange(false); injectTap(11, 11); bufferSurface->expectTap(1, 1); @@ -448,7 +504,10 @@ TEST_F(InputSurfacesTest, input_ignores_color_layer_alpha) { std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100); bgSurface->showAt(10, 10); + bgSurface->assertFocusChange(true); fgSurface->showAt(10, 10); + bgSurface->assertFocusChange(false); + fgSurface->assertFocusChange(true); injectTap(11, 11); fgSurface->expectTap(1, 1); @@ -465,12 +524,17 @@ TEST_F(InputSurfacesTest, input_respects_container_layer_visiblity) { InputSurface::makeContainerInputSurface(mComposerClient, 100, 100); bgSurface->showAt(10, 10); + bgSurface->assertFocusChange(true); containerSurface->showAt(10, 10); + bgSurface->assertFocusChange(false); + containerSurface->assertFocusChange(true); injectTap(11, 11); containerSurface->expectTap(1, 1); containerSurface->doTransaction([](auto &t, auto &sc) { t.hide(sc); }); + containerSurface->assertFocusChange(false); + bgSurface->assertFocusChange(true); injectTap(11, 11); bgSurface->expectTap(1, 1); @@ -479,9 +543,23 @@ TEST_F(InputSurfacesTest, input_respects_container_layer_visiblity) { TEST_F(InputSurfacesTest, input_respects_outscreen) { std::unique_ptr<InputSurface> surface = makeSurface(100, 100); surface->showAt(-1, -1); + surface->assertFocusChange(true); injectTap(0, 0); surface->expectTap(1, 1); } + +TEST_F(InputSurfacesTest, input_ignores_cursor_layer) { + std::unique_ptr<InputSurface> surface = makeSurface(100, 100); + std::unique_ptr<InputSurface> cursorSurface = + InputSurface::makeCursorInputSurface(mComposerClient, 10, 10); + + surface->showAt(10, 10); + surface->assertFocusChange(true); + cursorSurface->showAt(10, 10); + + injectTap(11, 11); + surface->expectTap(1, 1); +} } } diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp index aef7aed52c..15bd32d354 100644 --- a/libs/gui/tests/IGraphicBufferProducer_test.cpp +++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp @@ -17,7 +17,7 @@ #define LOG_TAG "IGraphicBufferProducer_test" //#define LOG_NDEBUG 0 -#include "DummyConsumer.h" +#include "MockConsumer.h" #include <gtest/gtest.h> @@ -89,7 +89,7 @@ protected: ALOGV("Begin test: %s.%s", testInfo->test_case_name(), testInfo->name()); - mDC = new DummyConsumer; + mMC = new MockConsumer; switch (GetParam()) { case USE_BUFFER_QUEUE_PRODUCER: { @@ -114,7 +114,7 @@ protected: } // Must connect consumer before producer connects will succeed. - ASSERT_OK(mConsumer->consumerConnect(mDC, /*controlledByApp*/false)); + ASSERT_OK(mConsumer->consumerConnect(mMC, /*controlledByApp*/ false)); } virtual void TearDown() { @@ -249,7 +249,7 @@ protected: } private: // hide from test body - sp<DummyConsumer> mDC; + sp<MockConsumer> mMC; protected: // accessible from test body sp<IGraphicBufferProducer> mProducer; @@ -543,7 +543,6 @@ TEST_P(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Succeeds) { // Should now be able to dequeue up to minBuffers times DequeueBufferResult result; for (int i = 0; i < minBuffers; ++i) { - EXPECT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & (dequeueBuffer(DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS, &result))) diff --git a/libs/gui/tests/Malicious.cpp b/libs/gui/tests/Malicious.cpp index acd42979c2..58d7cc6f35 100644 --- a/libs/gui/tests/Malicious.cpp +++ b/libs/gui/tests/Malicious.cpp @@ -129,7 +129,7 @@ private: int32_t mExpectedSlot = 0; }; -class DummyListener : public BnConsumerListener { +class FakeListener : public BnConsumerListener { public: void onFrameAvailable(const BufferItem&) override {} void onBuffersReleased() override {} @@ -140,7 +140,7 @@ sp<MaliciousBQP> getMaliciousBQP() { sp<IGraphicBufferProducer> producer; sp<IGraphicBufferConsumer> consumer; BufferQueue::createBufferQueue(&producer, &consumer); - sp<IConsumerListener> listener = new DummyListener; + sp<IConsumerListener> listener = new FakeListener; consumer->consumerConnect(listener, false); sp<MaliciousBQP> malicious = new MaliciousBQP(producer); diff --git a/libs/gui/tests/DummyConsumer.h b/libs/gui/tests/MockConsumer.h index 502bdf981b..4a6c51c17d 100644 --- a/libs/gui/tests/DummyConsumer.h +++ b/libs/gui/tests/MockConsumer.h @@ -18,7 +18,7 @@ namespace android { -struct DummyConsumer : public BnConsumerListener { +struct MockConsumer : public BnConsumerListener { void onFrameAvailable(const BufferItem& /* item */) override {} void onBuffersReleased() override {} void onSidebandStreamChanged() override {} diff --git a/libs/gui/tests/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp index d33ecfbdb9..6746b0a827 100644 --- a/libs/gui/tests/RegionSampling_test.cpp +++ b/libs/gui/tests/RegionSampling_test.cpp @@ -183,7 +183,7 @@ protected: mBackgroundLayer = mSurfaceComposerClient->createSurface(String8("Background RegionSamplingTest"), 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor); + ISurfaceComposerClient::eFXSurfaceEffect); uint32_t layerPositionBottom = 0x7E000000; SurfaceComposerClient::Transaction{} .setLayer(mBackgroundLayer, layerPositionBottom) @@ -240,6 +240,19 @@ protected: float const luma_gray = 0.50; }; +TEST_F(RegionSamplingTest, invalidLayerHandle_doesNotCrash) { + sp<ISurfaceComposer> composer = ComposerService::getComposerService(); + sp<Listener> listener = new Listener(); + const Rect sampleArea{100, 100, 200, 200}; + // Passing in composer service as the layer handle should not crash, we'll + // treat it as a layer that no longer exists and silently allow sampling to + // occur. + status_t status = composer->addRegionSamplingListener(sampleArea, + IInterface::asBinder(composer), listener); + ASSERT_EQ(NO_ERROR, status); + composer->removeRegionSamplingListener(listener); +} + TEST_F(RegionSamplingTest, DISABLED_CollectsLuma) { fill_render(rgba_green); @@ -297,4 +310,70 @@ TEST_F(RegionSamplingTest, DISABLED_CollectsLumaFromTwoRegions) { composer->removeRegionSamplingListener(grayListener); } +TEST_F(RegionSamplingTest, DISABLED_TestIfInvalidInputParameters) { + sp<ISurfaceComposer> composer = ComposerService::getComposerService(); + sp<Listener> listener = new Listener(); + const Rect sampleArea{100, 100, 200, 200}; + // Invalid input sampleArea + EXPECT_EQ(BAD_VALUE, + composer->addRegionSamplingListener(Rect::INVALID_RECT, mTopLayer->getHandle(), + listener)); + listener->reset(); + // Invalid input binder + EXPECT_EQ(NO_ERROR, composer->addRegionSamplingListener(sampleArea, NULL, listener)); + // Invalid input listener + EXPECT_EQ(BAD_VALUE, + composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), NULL)); + EXPECT_EQ(BAD_VALUE, composer->removeRegionSamplingListener(NULL)); + // remove the listener + composer->removeRegionSamplingListener(listener); +} + +TEST_F(RegionSamplingTest, DISABLED_TestCallbackAfterRemoveListener) { + fill_render(rgba_green); + sp<ISurfaceComposer> composer = ComposerService::getComposerService(); + sp<Listener> listener = new Listener(); + const Rect sampleArea{100, 100, 200, 200}; + composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener); + fill_render(rgba_green); + + EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received"; + EXPECT_NEAR(listener->luma(), luma_green, error_margin); + + listener->reset(); + composer->removeRegionSamplingListener(listener); + fill_render(rgba_green); + EXPECT_FALSE(listener->wait_event(100ms)) + << "callback should stop after remove the region sampling listener"; +} + +TEST_F(RegionSamplingTest, DISABLED_CollectsLumaFromMovingLayer) { + sp<ISurfaceComposer> composer = ComposerService::getComposerService(); + sp<Listener> listener = new Listener(); + Rect sampleArea{100, 100, 200, 200}; + + // Test: listener in (100, 100). See layer before move, no layer after move. + fill_render(rgba_blue); + composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener); + EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received"; + EXPECT_NEAR(listener->luma(), luma_blue, error_margin); + listener->reset(); + SurfaceComposerClient::Transaction{}.setPosition(mContentLayer, 600, 600).apply(); + EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received"; + EXPECT_NEAR(listener->luma(), luma_gray, error_margin); + composer->removeRegionSamplingListener(listener); + + // Test: listener offset to (600, 600). No layer before move, see layer after move. + fill_render(rgba_green); + sampleArea.offsetTo(600, 600); + composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener); + EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received"; + EXPECT_NEAR(listener->luma(), luma_gray, error_margin); + listener->reset(); + SurfaceComposerClient::Transaction{}.setPosition(mContentLayer, 600, 600).apply(); + EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received"; + EXPECT_NEAR(listener->luma(), luma_green, error_margin); + composer->removeRegionSamplingListener(listener); +} + } // namespace android::test diff --git a/libs/gui/tests/SamplingDemo.cpp b/libs/gui/tests/SamplingDemo.cpp index 9891587fe2..5c1bebb960 100644 --- a/libs/gui/tests/SamplingDemo.cpp +++ b/libs/gui/tests/SamplingDemo.cpp @@ -39,7 +39,7 @@ public: sp<SurfaceComposerClient> client = new SurfaceComposerClient; mButton = client->createSurface(String8(name), 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor); + ISurfaceComposerClient::eFXSurfaceEffect); const int32_t width = samplingArea.getWidth(); const int32_t height = samplingArea.getHeight(); @@ -55,7 +55,7 @@ public: .apply(); mButtonBlend = client->createSurface(String8(name) + "Blend", 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor); + ISurfaceComposerClient::eFXSurfaceEffect); SurfaceComposerClient::Transaction{} .setLayer(mButtonBlend, 0x7ffffffe) @@ -73,7 +73,7 @@ public: if (HIGHLIGHT_SAMPLING_AREA) { mSamplingArea = client->createSurface(String8("SamplingArea"), 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor); + ISurfaceComposerClient::eFXSurfaceEffect); SurfaceComposerClient::Transaction{} .setLayer(mSamplingArea, 0x7ffffffd) diff --git a/libs/gui/tests/StreamSplitter_test.cpp b/libs/gui/tests/StreamSplitter_test.cpp index ad6e051684..b65cddaea3 100644 --- a/libs/gui/tests/StreamSplitter_test.cpp +++ b/libs/gui/tests/StreamSplitter_test.cpp @@ -48,7 +48,7 @@ protected: } }; -struct DummyListener : public BnConsumerListener { +struct FakeListener : public BnConsumerListener { virtual void onFrameAvailable(const BufferItem& /* item */) {} virtual void onBuffersReleased() {} virtual void onSidebandStreamChanged() {} @@ -64,7 +64,7 @@ TEST_F(StreamSplitterTest, OneInputOneOutput) { sp<IGraphicBufferProducer> outputProducer; sp<IGraphicBufferConsumer> outputConsumer; BufferQueue::createBufferQueue(&outputProducer, &outputConsumer); - ASSERT_EQ(OK, outputConsumer->consumerConnect(new DummyListener, false)); + ASSERT_EQ(OK, outputConsumer->consumerConnect(new FakeListener, false)); sp<StreamSplitter> splitter; status_t status = StreamSplitter::createSplitter(inputConsumer, &splitter); @@ -75,8 +75,9 @@ TEST_F(StreamSplitterTest, OneInputOneOutput) { ASSERT_EQ(OK, outputProducer->allowAllocation(false)); IGraphicBufferProducer::QueueBufferOutput qbOutput; - ASSERT_EQ(OK, inputProducer->connect(new DummyProducerListener, - NATIVE_WINDOW_API_CPU, false, &qbOutput)); + ASSERT_EQ(OK, + inputProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false, + &qbOutput)); int slot; sp<Fence> fence; @@ -132,8 +133,7 @@ TEST_F(StreamSplitterTest, OneInputMultipleOutputs) { for (int output = 0; output < NUM_OUTPUTS; ++output) { BufferQueue::createBufferQueue(&outputProducers[output], &outputConsumers[output]); - ASSERT_EQ(OK, outputConsumers[output]->consumerConnect( - new DummyListener, false)); + ASSERT_EQ(OK, outputConsumers[output]->consumerConnect(new FakeListener, false)); } sp<StreamSplitter> splitter; @@ -147,8 +147,9 @@ TEST_F(StreamSplitterTest, OneInputMultipleOutputs) { } IGraphicBufferProducer::QueueBufferOutput qbOutput; - ASSERT_EQ(OK, inputProducer->connect(new DummyProducerListener, - NATIVE_WINDOW_API_CPU, false, &qbOutput)); + ASSERT_EQ(OK, + inputProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false, + &qbOutput)); int slot; sp<Fence> fence; @@ -203,7 +204,7 @@ TEST_F(StreamSplitterTest, OutputAbandonment) { sp<IGraphicBufferProducer> outputProducer; sp<IGraphicBufferConsumer> outputConsumer; BufferQueue::createBufferQueue(&outputProducer, &outputConsumer); - ASSERT_EQ(OK, outputConsumer->consumerConnect(new DummyListener, false)); + ASSERT_EQ(OK, outputConsumer->consumerConnect(new FakeListener, false)); sp<StreamSplitter> splitter; status_t status = StreamSplitter::createSplitter(inputConsumer, &splitter); @@ -211,8 +212,9 @@ TEST_F(StreamSplitterTest, OutputAbandonment) { ASSERT_EQ(OK, splitter->addOutput(outputProducer)); IGraphicBufferProducer::QueueBufferOutput qbOutput; - ASSERT_EQ(OK, inputProducer->connect(new DummyProducerListener, - NATIVE_WINDOW_API_CPU, false, &qbOutput)); + ASSERT_EQ(OK, + inputProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false, + &qbOutput)); int slot; sp<Fence> fence; diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp index 65e09f2540..c7458a3755 100644 --- a/libs/gui/tests/SurfaceTextureClient_test.cpp +++ b/libs/gui/tests/SurfaceTextureClient_test.cpp @@ -28,8 +28,6 @@ #include <utils/Log.h> #include <utils/Thread.h> -extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); - namespace android { class SurfaceTextureClientTest : public ::testing::Test { @@ -56,7 +54,7 @@ protected: mANW = mSTC; // We need a valid GL context so we can test updateTexImage() - // This initializes EGL and create a dummy GL context with a + // This initializes EGL and create a GL context placeholder with a // pbuffer render target. mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); ASSERT_EQ(EGL_SUCCESS, eglGetError()); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index a8516872fd..592913c46b 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -14,22 +14,23 @@ * limitations under the License. */ -#include "DummyConsumer.h" +#include "MockConsumer.h" #include <gtest/gtest.h> +#include <SurfaceFlingerProperties.h> #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> #include <binder/ProcessState.h> #include <configstore/Utils.h> -#include <cutils/properties.h> -#include <inttypes.h> #include <gui/BufferItemConsumer.h> #include <gui/IDisplayEventConnection.h> #include <gui/IProducerListener.h> #include <gui/ISurfaceComposer.h> #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> +#include <inttypes.h> #include <private/gui/ComposerService.h> +#include <ui/BufferQueueDefs.h> #include <ui/Rect.h> #include <utils/String8.h> @@ -46,23 +47,20 @@ using ui::ColorMode; using Transaction = SurfaceComposerClient::Transaction; -static bool hasWideColorDisplay = - getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false); +static bool hasWideColorDisplay = android::sysprop::has_wide_color_display(false); -static bool hasHdrDisplay = - getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasHDRDisplay>(false); +static bool hasHdrDisplay = android::sysprop::has_HDR_display(false); class FakeSurfaceComposer; class FakeProducerFrameEventHistory; static constexpr uint64_t NO_FRAME_INDEX = std::numeric_limits<uint64_t>::max(); -class DummySurfaceListener : public SurfaceListener { +class FakeSurfaceListener : public SurfaceListener { public: - DummySurfaceListener(bool enableReleasedCb = false) : - mEnableReleaseCb(enableReleasedCb), - mBuffersReleased(0) {} - virtual ~DummySurfaceListener() = default; + FakeSurfaceListener(bool enableReleasedCb = false) + : mEnableReleaseCb(enableReleasedCb), mBuffersReleased(0) {} + virtual ~FakeSurfaceListener() = default; virtual void onBufferReleased() { mBuffersReleased++; @@ -125,15 +123,15 @@ protected: sp<IGraphicBufferConsumer> consumer; BufferQueue::createBufferQueue(&producer, &consumer); - sp<DummyConsumer> dummyConsumer(new DummyConsumer); - consumer->consumerConnect(dummyConsumer, false); + sp<MockConsumer> mockConsumer(new MockConsumer); + consumer->consumerConnect(mockConsumer, false); consumer->setConsumerName(String8("TestConsumer")); sp<Surface> surface = new Surface(producer); sp<ANativeWindow> window(surface); - sp<DummySurfaceListener> listener; + sp<FakeSurfaceListener> listener; if (hasSurfaceListener) { - listener = new DummySurfaceListener(enableReleasedCb); + listener = new FakeSurfaceListener(enableReleasedCb); } ASSERT_EQ(OK, surface->connect( NATIVE_WINDOW_API_CPU, @@ -382,8 +380,8 @@ TEST_F(SurfaceTest, GetConsumerName) { sp<IGraphicBufferConsumer> consumer; BufferQueue::createBufferQueue(&producer, &consumer); - sp<DummyConsumer> dummyConsumer(new DummyConsumer); - consumer->consumerConnect(dummyConsumer, false); + sp<MockConsumer> mockConsumer(new MockConsumer); + consumer->consumerConnect(mockConsumer, false); consumer->setConsumerName(String8("TestConsumer")); sp<Surface> surface = new Surface(producer); @@ -398,8 +396,8 @@ TEST_F(SurfaceTest, GetWideColorSupport) { sp<IGraphicBufferConsumer> consumer; BufferQueue::createBufferQueue(&producer, &consumer); - sp<DummyConsumer> dummyConsumer(new DummyConsumer); - consumer->consumerConnect(dummyConsumer, false); + sp<MockConsumer> mockConsumer(new MockConsumer); + consumer->consumerConnect(mockConsumer, false); consumer->setConsumerName(String8("TestConsumer")); sp<Surface> surface = new Surface(producer); @@ -429,8 +427,8 @@ TEST_F(SurfaceTest, GetHdrSupport) { sp<IGraphicBufferConsumer> consumer; BufferQueue::createBufferQueue(&producer, &consumer); - sp<DummyConsumer> dummyConsumer(new DummyConsumer); - consumer->consumerConnect(dummyConsumer, false); + sp<MockConsumer> mockConsumer(new MockConsumer); + consumer->consumerConnect(mockConsumer, false); consumer->setConsumerName(String8("TestConsumer")); sp<Surface> surface = new Surface(producer); @@ -453,8 +451,8 @@ TEST_F(SurfaceTest, SetHdrMetadata) { sp<IGraphicBufferConsumer> consumer; BufferQueue::createBufferQueue(&producer, &consumer); - sp<DummyConsumer> dummyConsumer(new DummyConsumer); - consumer->consumerConnect(dummyConsumer, false); + sp<MockConsumer> mockConsumer(new MockConsumer); + consumer->consumerConnect(mockConsumer, false); consumer->setConsumerName(String8("TestConsumer")); sp<Surface> surface = new Surface(producer); @@ -498,8 +496,8 @@ TEST_F(SurfaceTest, DynamicSetBufferCount) { sp<IGraphicBufferConsumer> consumer; BufferQueue::createBufferQueue(&producer, &consumer); - sp<DummyConsumer> dummyConsumer(new DummyConsumer); - consumer->consumerConnect(dummyConsumer, false); + sp<MockConsumer> mockConsumer(new MockConsumer); + consumer->consumerConnect(mockConsumer, false); consumer->setConsumerName(String8("TestConsumer")); sp<Surface> surface = new Surface(producer); @@ -524,13 +522,13 @@ TEST_F(SurfaceTest, GetAndFlushRemovedBuffers) { sp<IGraphicBufferConsumer> consumer; BufferQueue::createBufferQueue(&producer, &consumer); - sp<DummyConsumer> dummyConsumer(new DummyConsumer); - consumer->consumerConnect(dummyConsumer, false); + sp<MockConsumer> mockConsumer(new MockConsumer); + consumer->consumerConnect(mockConsumer, false); consumer->setConsumerName(String8("TestConsumer")); sp<Surface> surface = new Surface(producer); sp<ANativeWindow> window(surface); - sp<DummyProducerListener> listener = new DummyProducerListener(); + sp<StubProducerListener> listener = new StubProducerListener(); ASSERT_EQ(OK, surface->connect( NATIVE_WINDOW_API_CPU, /*listener*/listener, @@ -617,7 +615,7 @@ TEST_F(SurfaceTest, TestGetLastDequeueStartTime) { anw->dequeueBuffer(anw.get(), &buffer, &fenceFd); nsecs_t after = systemTime(CLOCK_MONOTONIC); - nsecs_t lastDequeueTime = mSurface->getLastDequeueStartTime(); + nsecs_t lastDequeueTime = ANativeWindow_getLastDequeueStartTime(anw.get()); ASSERT_LE(before, lastDequeueTime); ASSERT_GE(after, lastDequeueTime); } @@ -688,6 +686,7 @@ public: const sp<IBinder>& /*applyToken*/, const InputWindowCommands& /*inputWindowCommands*/, int64_t /*desiredPresentTime*/, const client_cache_t& /*cachedBuffer*/, + bool /*hasListenerCallbacks*/, const std::vector<ListenerCallbacks>& /*listenerCallbacks*/) override { } @@ -717,15 +716,18 @@ public: } void setPowerMode(const sp<IBinder>& /*display*/, int /*mode*/) override {} - status_t getDisplayConfigs(const sp<IBinder>& /*display*/, - Vector<DisplayInfo>* /*configs*/) override { return NO_ERROR; } + status_t getDisplayInfo(const sp<IBinder>& /*display*/, DisplayInfo*) override { + return NO_ERROR; + } + status_t getDisplayConfigs(const sp<IBinder>& /*display*/, Vector<DisplayConfig>*) override { + return NO_ERROR; + } + status_t getDisplayState(const sp<IBinder>& /*display*/, ui::DisplayState*) override { + return NO_ERROR; + } status_t getDisplayStats(const sp<IBinder>& /*display*/, DisplayStatInfo* /*stats*/) override { return NO_ERROR; } int getActiveConfig(const sp<IBinder>& /*display*/) override { return 0; } - status_t setActiveConfig(const sp<IBinder>& /*display*/, int /*id*/) - override { - return NO_ERROR; - } status_t getDisplayColorModes(const sp<IBinder>& /*display*/, Vector<ColorMode>* /*outColorModes*/) override { return NO_ERROR; @@ -741,21 +743,30 @@ public: status_t setActiveColorMode(const sp<IBinder>& /*display*/, ColorMode /*colorMode*/) override { return NO_ERROR; } status_t captureScreen(const sp<IBinder>& /*display*/, sp<GraphicBuffer>* /*outBuffer*/, - bool& /* outCapturedSecureLayers */, - const ui::Dataspace /*reqDataspace*/, - const ui::PixelFormat /*reqPixelFormat*/, Rect /*sourceCrop*/, + bool& /*outCapturedSecureLayers*/, ui::Dataspace /*reqDataspace*/, + ui::PixelFormat /*reqPixelFormat*/, const Rect& /*sourceCrop*/, uint32_t /*reqWidth*/, uint32_t /*reqHeight*/, - bool /*useIdentityTransform*/, Rotation /*rotation*/, + bool /*useIdentityTransform*/, ui::Rotation, bool /*captureSecureLayers*/) override { return NO_ERROR; } + status_t getAutoLowLatencyModeSupport(const sp<IBinder>& /*display*/, + bool* /*outSupport*/) const override { + return NO_ERROR; + } + void setAutoLowLatencyMode(const sp<IBinder>& /*display*/, bool /*on*/) override {} + status_t getGameContentTypeSupport(const sp<IBinder>& /*display*/, + bool* /*outSupport*/) const override { + return NO_ERROR; + } + void setGameContentType(const sp<IBinder>& /*display*/, bool /*on*/) override {} status_t captureScreen(uint64_t /*displayOrLayerStack*/, ui::Dataspace* /*outDataspace*/, sp<GraphicBuffer>* /*outBuffer*/) override { return NO_ERROR; } virtual status_t captureLayers( const sp<IBinder>& /*parentHandle*/, sp<GraphicBuffer>* /*outBuffer*/, - const ui::Dataspace /*reqDataspace*/, const ui::PixelFormat /*reqPixelFormat*/, + ui::Dataspace /*reqDataspace*/, ui::PixelFormat /*reqPixelFormat*/, const Rect& /*sourceCrop*/, const std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>>& /*excludeHandles*/, @@ -774,7 +785,7 @@ public: return NO_ERROR; } status_t injectVSync(nsecs_t /*when*/) override { return NO_ERROR; } - status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* /*layers*/) const override { + status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* /*layers*/) override { return NO_ERROR; } status_t getCompositionPreference( @@ -791,7 +802,7 @@ public: } status_t setDisplayContentSamplingEnabled(const sp<IBinder>& /*display*/, bool /*enable*/, uint8_t /*componentMask*/, - uint64_t /*maxFrames*/) const override { + uint64_t /*maxFrames*/) override { return NO_ERROR; } status_t getDisplayedContentSample(const sp<IBinder>& /*display*/, uint64_t /*maxFrames*/, @@ -809,7 +820,7 @@ public: return NO_ERROR; } status_t setDisplayBrightness(const sp<IBinder>& /*displayToken*/, - float /*brightness*/) const override { + float /*brightness*/) override { return NO_ERROR; } @@ -822,16 +833,37 @@ public: const sp<IRegionSamplingListener>& /*listener*/) override { return NO_ERROR; } - status_t setAllowedDisplayConfigs(const sp<IBinder>& /*displayToken*/, - const std::vector<int32_t>& /*allowedConfigs*/) override { + status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& /*displayToken*/, + int32_t /*defaultConfig*/, + float /*primaryRefreshRateMin*/, + float /*primaryRefreshRateMax*/, + float /*appRequestRefreshRateMin*/, + float /*appRequestRefreshRateMax*/) { return NO_ERROR; } - status_t getAllowedDisplayConfigs(const sp<IBinder>& /*displayToken*/, - std::vector<int32_t>* /*outAllowedConfigs*/) override { + status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& /*displayToken*/, + int32_t* /*outDefaultConfig*/, + float* /*outPrimaryRefreshRateMin*/, + float* /*outPrimaryRefreshRateMax*/, + float* /*outAppRequestRefreshRateMin*/, + float* /*outAppRequestRefreshRateMax*/) override { return NO_ERROR; - } + }; status_t notifyPowerHint(int32_t /*hintId*/) override { return NO_ERROR; } + status_t setGlobalShadowSettings(const half4& /*ambientColor*/, const half4& /*spotColor*/, + float /*lightPosY*/, float /*lightPosZ*/, + float /*lightRadius*/) override { + return NO_ERROR; + } + + status_t setFrameRate(const sp<IGraphicBufferProducer>& /*surface*/, float /*frameRate*/, + int8_t /*compatibility*/) override { + return NO_ERROR; + } + + status_t acquireFrameRateFlexibilityToken(sp<IBinder>* /*outToken*/) { return NO_ERROR; } + protected: IBinder* onAsBinder() override { return nullptr; } @@ -1872,4 +1904,99 @@ TEST_F(GetFrameTimestampsTest, PresentUnsupportedNoSync) { EXPECT_EQ(-1, outDisplayPresentTime); } +TEST_F(SurfaceTest, DequeueWithConsumerDrivenSize) { + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + sp<MockConsumer> mockConsumer(new MockConsumer); + consumer->consumerConnect(mockConsumer, false); + consumer->setDefaultBufferSize(10, 10); + + sp<Surface> surface = new Surface(producer); + sp<ANativeWindow> window(surface); + native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU); + native_window_set_buffers_dimensions(window.get(), 0, 0); + + int fence; + ANativeWindowBuffer* buffer; + + // Buffer size is driven by the consumer + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(10, buffer->width); + EXPECT_EQ(10, buffer->height); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence)); + + // Buffer size is driven by the consumer + consumer->setDefaultBufferSize(10, 20); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(10, buffer->width); + EXPECT_EQ(20, buffer->height); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence)); + + // Transform hint isn't synced to producer before queueBuffer or connect + consumer->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_270); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(10, buffer->width); + EXPECT_EQ(20, buffer->height); + ASSERT_EQ(NO_ERROR, window->queueBuffer(window.get(), buffer, fence)); + + // Transform hint is synced to producer but no auto prerotation + consumer->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_270); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(10, buffer->width); + EXPECT_EQ(20, buffer->height); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence)); + + // Prerotation is driven by the consumer with the transform hint used by producer + native_window_set_auto_prerotation(window.get(), true); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(20, buffer->width); + EXPECT_EQ(10, buffer->height); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence)); + + // Turn off auto prerotaton + native_window_set_auto_prerotation(window.get(), false); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(10, buffer->width); + EXPECT_EQ(20, buffer->height); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence)); + + // Test auto prerotation bit is disabled after disconnect + native_window_set_auto_prerotation(window.get(), true); + native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_CPU); + native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU); + consumer->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_270); + native_window_set_buffers_dimensions(window.get(), 0, 0); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(10, buffer->width); + EXPECT_EQ(20, buffer->height); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence)); +} + +TEST_F(SurfaceTest, DefaultMaxBufferCountSetAndUpdated) { + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + sp<MockConsumer> mockConsumer(new MockConsumer); + consumer->consumerConnect(mockConsumer, false); + + sp<Surface> surface = new Surface(producer); + sp<ANativeWindow> window(surface); + + int count = -1; + ASSERT_EQ(NO_ERROR, window->query(window.get(), NATIVE_WINDOW_MAX_BUFFER_COUNT, &count)); + EXPECT_EQ(BufferQueueDefs::NUM_BUFFER_SLOTS, count); + + consumer->setMaxBufferCount(10); + ASSERT_EQ(NO_ERROR, native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU)); + EXPECT_EQ(NO_ERROR, window->query(window.get(), NATIVE_WINDOW_MAX_BUFFER_COUNT, &count)); + EXPECT_EQ(10, count); + + ASSERT_EQ(NO_ERROR, native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_CPU)); + ASSERT_EQ(NO_ERROR, window->query(window.get(), NATIVE_WINDOW_MAX_BUFFER_COUNT, &count)); + EXPECT_EQ(BufferQueueDefs::NUM_BUFFER_SLOTS, count); +} + } // namespace android |