Merge Android R (rvc-dev-plus-aosp-without-vendor@6692709)
Bug: 166295507
Merged-In: I70ea776b8589ac3a7982c710c5c8b2941d86e55b
Change-Id: Ic1d535e9d2d6f80d95215240dbdb024995b045f8
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 9fc16ba..4a4510e 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -41,17 +41,26 @@
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 @@
"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 @@
"libdvr_headers",
"libpdx_headers",
],
+
+ aidl: {
+ export_aidl_headers: true,
+ }
}
// Used by media codec services exclusively as a static lib for
@@ -115,9 +138,37 @@
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 @@
},
},
- 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 @@
"android.hardware.graphics.common@1.2",
"android.hidl.token@1.0-utils",
"libbase",
- "libbinder",
"libcutils",
"libEGL",
"libGLESv2",
@@ -206,7 +228,6 @@
],
export_shared_lib_headers: [
- "libbinder",
"libEGL",
"libnativewindow",
"libui",
@@ -226,4 +247,21 @@
],
}
+// 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 0000000..56591bd
--- /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 4be014f..1f71e23 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 @@
// 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 5fb3f0b..c1d92a2 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -43,6 +43,27 @@
}
}
+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 3a7cb44..da6143c 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 @@
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::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 @@
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 0264bd2..5023b6b 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 @@
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 @@
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("%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("\n%sFIFO(%zu):\n", prefix.string(), mQueue.size());
+ 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 4f8eb6b..a7cf39a 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
mCore->mLinkedToDeath = listener;
}
+#endif
mCore->mConnectedProducerListener = listener;
mCore->mBufferReleasedCbEnabled = listener->needsReleaseNotify();
}
@@ -1289,6 +1335,7 @@
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 @@
token->unlinkToDeath(
static_cast<IBinder::DeathRecipient*>(this));
}
+#endif
mCore->mSharedBufferSlot =
BufferQueueCore::INVALID_BUFFER_SLOT;
mCore->mLinkedToDeath = nullptr;
@@ -1306,6 +1354,7 @@
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 @@
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 @@
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 @@
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 @@
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 c13030b..976c9b9 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 abd9921..9f91d9d 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -101,6 +101,48 @@
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 ab6f364..5762dab 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 @@
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 0000000..b33bc9e
--- /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 b8faa2d..1fed509 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -79,6 +79,13 @@
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 3215eca..e2ea3f9 100644
--- a/libs/gui/FrameTimestamps.cpp
+++ b/libs/gui/FrameTimestamps.cpp
@@ -364,6 +364,10 @@
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 8199c98..30d19e3 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 @@
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 add3ef0..058cd9a 100644
--- a/libs/gui/HdrMetadata.cpp
+++ b/libs/gui/HdrMetadata.cpp
@@ -28,8 +28,8 @@
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 @@
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 @@
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 85ac304..f3bd90c 100644
--- a/libs/gui/IConsumerListener.cpp
+++ b/libs/gui/IConsumerListener.cpp
@@ -28,7 +28,10 @@
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 @@
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 @@
// 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 @@
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 c0e246f..aa74bfd 100644
--- a/libs/gui/IDisplayEventConnection.cpp
+++ b/libs/gui/IDisplayEventConnection.cpp
@@ -26,7 +26,8 @@
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 @@
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 @@
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 0e03b7d..ad00939 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -73,6 +73,7 @@
GET_UNIQUE_ID,
GET_CONSUMER_USAGE,
SET_LEGACY_BUFFER_DROP,
+ SET_AUTO_PREROTATION,
};
class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@@ -547,6 +548,17 @@
}
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 @@
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 @@
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 @@
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 @@
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 808e336..0683087 100644
--- a/libs/gui/IProducerListener.cpp
+++ b/libs/gui/IProducerListener.cpp
@@ -119,9 +119,7 @@
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 12deaf0..e62a61f 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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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.writeInt32Vector(allowedConfigs);
+ result = data.writeInt32(defaultConfig);
if (result != NO_ERROR) {
- ALOGE("setAllowedDisplayConfigs failed to writeInt32Vector: %d", result);
+ ALOGE("setDesiredDisplayConfigSpecs failed to write defaultConfig: %d", result);
return result;
}
- result = remote()->transact(BnSurfaceComposer::SET_ALLOWED_DISPLAY_CONFIGS, data, &reply);
+ result = data.writeFloat(primaryRefreshRateMin);
if (result != NO_ERROR) {
- ALOGE("setAllowedDisplayConfigs failed to transact: %d", result);
+ 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.writeFloat(appRequestRefreshRateMin);
+ if (result != NO_ERROR) {
+ ALOGE("setDesiredDisplayConfigSpecs failed to write appRequestRefreshRateMin: %d",
+ result);
+ return result;
+ }
+ result = data.writeFloat(appRequestRefreshRateMax);
+ if (result != NO_ERROR) {
+ 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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
}
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 129558b..621cf59 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -34,7 +34,8 @@
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 @@
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 @@
&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 @@
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 74cd4f1..69f7894 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -30,6 +30,66 @@
} // 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 @@
} 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 @@
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 @@
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 04d2871..b3eb994 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 @@
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 42eb921..0281279 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 @@
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 @@
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 @@
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 @@
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 @@
DisplayState::DisplayState() :
what(0),
layerStack(0),
- orientation(eOrientationDefault),
viewport(Rect::EMPTY_RECT),
frame(Rect::EMPTY_RECT),
width(0),
@@ -194,7 +231,7 @@
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 @@
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 @@
}
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 @@
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 @@
what |= eOverrideScalingModeChanged;
overrideScalingMode = other.overrideScalingMode;
}
- if (other.what & eGeometryAppliesWithResize) {
- what |= eGeometryAppliesWithResize;
- }
if (other.what & eReparentChildren) {
what |= eReparentChildren;
reparentHandle = other.reparentHandle;
@@ -365,7 +404,6 @@
}
if (other.what & eHasListenerCallbacksChanged) {
what |= eHasListenerCallbacksChanged;
- hasListenerCallbacks = other.hasListenerCallbacks;
}
#ifndef NO_INPUT
@@ -389,6 +427,23 @@
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 @@
// ------------------------------- 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 0000000..30f0ef6
--- /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 b822319..c3323fe 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 @@
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 @@
mConnectedToCpu = false;
mProducerControlledByApp = controlledByApp;
mSwapIntervalZero = false;
+ mMaxBufferCount = NUM_BUFFER_SLOTS;
}
Surface::~Surface() {
@@ -365,18 +379,58 @@
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 @@
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 @@
*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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 dfc6185..83bc069 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::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 @@
evictLeastRecentlyUsedBuffer();
}
- buffer->addDeathCallback(bufferCacheCallback, nullptr);
+ buffer->addDeathCallback(removeDeadBufferCallback, nullptr);
mBuffers[buffer->getId()] = getCounter();
return buffer->getId();
@@ -310,7 +341,7 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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::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 @@
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 @@
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 @@
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,11 +1432,58 @@
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;
+}
+
// ---------------------------------------------------------------------------
DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) {
@@ -1242,9 +1525,9 @@
}
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 @@
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<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 @@
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 @@
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 @@
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 @@
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 @@
return ComposerService::getComposerService()->getActiveConfig(display);
}
-status_t SurfaceComposerClient::setActiveConfig(const sp<IBinder>& display, int id) {
- return ComposerService::getComposerService()->setActiveConfig(display, id);
+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::setAllowedDisplayConfigs(
- const sp<IBinder>& displayToken, const std::vector<int32_t>& allowedConfigs) {
- return ComposerService::getComposerService()->setAllowedDisplayConfigs(displayToken,
- allowedConfigs);
-}
-
-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 @@
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 @@
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 @@
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::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 @@
excludeHandles, frameScale, true /* childrenOnly */);
return ret;
}
-// ----------------------------------------------------------------------------
-}; // namespace android
+
+} // namespace android
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 55488da..a332a1f 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -45,42 +45,23 @@
// 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<IBinder> SurfaceControl::getHandle() const
{
- Mutex::Autolock lock(mLock);
return mHandle;
}
@@ -179,15 +159,25 @@
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<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 0000000..1c43530
--- /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 5cb3593..3e20a37 100644
--- a/libs/gui/bufferqueue/1.0/Conversion.cpp
+++ b/libs/gui/bufferqueue/1.0/Conversion.cpp
@@ -109,20 +109,6 @@
}
/**
- * \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 @@
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 2712f42..598c8de 100644
--- a/libs/gui/bufferqueue/1.0/H2BProducerListener.cpp
+++ b/libs/gui/bufferqueue/1.0/H2BProducerListener.cpp
@@ -32,7 +32,11 @@
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 78dc4e8..56b64b9 100644
--- a/libs/gui/bufferqueue/1.0/WProducerListener.cpp
+++ b/libs/gui/bufferqueue/1.0/WProducerListener.cpp
@@ -46,5 +46,7 @@
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 e891ec5..c76d771 100644
--- a/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp
+++ b/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp
@@ -249,6 +249,24 @@
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 @@
&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 @@
}
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 b81a357..b2bd117 100644
--- a/libs/gui/bufferqueue/2.0/H2BProducerListener.cpp
+++ b/libs/gui/bufferqueue/2.0/H2BProducerListener.cpp
@@ -32,7 +32,11 @@
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 @@
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 0000000..2320771
--- /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 da95274..91f80d2 100644
--- a/libs/gui/include/gui/BufferQueue.h
+++ b/libs/gui/include/gui/BufferQueue.h
@@ -63,6 +63,9 @@
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 17617bc..557c28b 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 @@
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 d2a47a6..a7f7d1d 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 @@
// 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 366ced3..8ff0cd0 100644
--- a/libs/gui/include/gui/ConsumerBase.h
+++ b/libs/gui/include/gui/ConsumerBase.h
@@ -45,6 +45,9 @@
// 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 @@
// 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 0000000..f210c34
--- /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 a558cf9..8d49184 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -65,6 +65,7 @@
struct VSync {
uint32_t count;
+ nsecs_t expectedVSyncTimestamp;
};
struct Hotplug {
@@ -73,6 +74,7 @@
struct Config {
int32_t configId;
+ nsecs_t vsyncPeriod;
};
Header header;
@@ -144,6 +146,12 @@
*/
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 4670edd..0750080 100644
--- a/libs/gui/include/gui/FrameTimestamps.h
+++ b/libs/gui/include/gui/FrameTimestamps.h
@@ -175,7 +175,6 @@
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 @@
~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 ddd868d..2f538ff 100644
--- a/libs/gui/include/gui/GLConsumer.h
+++ b/libs/gui/include/gui/GLConsumer.h
@@ -499,7 +499,7 @@
// 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 c082882..0ab2399 100644
--- a/libs/gui/include/gui/IConsumerListener.h
+++ b/libs/gui/include/gui/IConsumerListener.h
@@ -43,6 +43,17 @@
// 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 @@
FrameEventHistoryDelta* /*outDelta*/) {}
};
+#ifndef NO_BINDER
class IConsumerListener : public ConsumerListener, public IInterface {
public:
DECLARE_META_INTERFACE(ConsumerListener)
@@ -94,4 +106,11 @@
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 d783f74..674aafd 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 @@
* 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 9fb7580..0b92e7d 100644
--- a/libs/gui/include/gui/IGraphicBufferConsumer.h
+++ b/libs/gui/include/gui/IGraphicBufferConsumer.h
@@ -35,10 +35,14 @@
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 @@
}
};
+#ifndef NO_BINDER
class BnGraphicBufferConsumer : public SafeBnInterface<IGraphicBufferConsumer> {
public:
BnGraphicBufferConsumer()
@@ -290,5 +295,9 @@
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 3dde8c8..45e0a13 100644
--- a/libs/gui/include/gui/IGraphicBufferProducer.h
+++ b/libs/gui/include/gui/IGraphicBufferProducer.h
@@ -45,6 +45,13 @@
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 @@
*
* 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 @@
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 @@
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 @@
// 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 @@
// 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 @@
// 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 @@
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 32a3690..f7ffbb9 100644
--- a/libs/gui/include/gui/IProducerListener.h
+++ b/libs/gui/include/gui/IProducerListener.h
@@ -51,6 +51,7 @@
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 @@
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 c84910b..8d3160a 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 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 @@
public:
DECLARE_META_INTERFACE(SurfaceComposer)
+ static constexpr size_t MAX_LAYERS = 4096;
+
// flags for setTransactionState()
enum {
eSynchronous = 0x01,
- eAnimation = 0x02,
+ 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
- };
+ // DEPRECATED - use eExplicitEarlyWakeup[Start|End]
+ eEarlyWakeup = 0x04,
- enum Rotation {
- eRotateNone = 0,
- eRotate90 = 1,
- eRotate180 = 2,
- eRotate270 = 3
+ // 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 @@
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 @@
*/
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 @@
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 @@
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 @@
* 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 @@
* 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 @@
*/
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 @@
*
* 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 @@
*/
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 @@
*/
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
+ /* 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 setAllowedDisplayConfigs(const sp<IBinder>& displayToken,
- const std::vector<int32_t>& allowedConfigs) = 0;
+ virtual status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
+ int32_t defaultConfig,
+ float primaryRefreshRateMin,
+ float primaryRefreshRateMax,
+ float appRequestRefreshRateMin,
+ float appRequestRefreshRateMax) = 0;
- /*
- * Returns the allowed display configurations currently set.
- * The allowedConfigs in a vector of indexes corresponding to the configurations
- * returned from getDisplayConfigs().
- */
- virtual status_t getAllowedDisplayConfigs(const sp<IBinder>& displayToken,
- std::vector<int32_t>* outAllowedConfigs) = 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 @@
* 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 @@
* 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 @@
// 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 @@
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 @@
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 @@
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 32ac9e8..3afbabf 100644
--- a/libs/gui/include/gui/ISurfaceComposerClient.h
+++ b/libs/gui/include/gui/ISurfaceComposerClient.h
@@ -33,7 +33,7 @@
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 @@
eProtectedByApp = 0x00000800,
eProtectedByDRM = 0x00001000,
eCursorWindow = 0x00002000,
+ eNoColorFill = 0x00004000,
eFXSurfaceBufferQueue = 0x00000000,
- eFXSurfaceColor = 0x00020000,
+ eFXSurfaceEffect = 0x00020000,
eFXSurfaceBufferState = 0x00040000,
eFXSurfaceContainer = 0x00080000,
eFXSurfaceMask = 0x000F0000,
@@ -56,7 +57,7 @@
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 @@
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 @@
* 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 774ad46..c58634b 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 @@
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 @@
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 f438eb3..e60f677 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 @@
eCropChanged_legacy = 0x00000100,
eDeferTransaction_legacy = 0x00000200,
eOverrideScalingModeChanged = 0x00000400,
- eGeometryAppliesWithResize = 0x00000800,
+ eShadowRadiusChanged = 0x00000800,
eReparentChildren = 0x00001000,
eDetachChildren = 0x00002000,
eRelativeLayerChanged = 0x00004000,
@@ -97,6 +100,11 @@
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 @@
reserved(0),
crop_legacy(Rect::INVALID_RECT),
cornerRadius(0.0f),
+ backgroundBlurRadius(0),
frameNumber_legacy(0),
overrideScalingMode(-1),
transform(0),
@@ -123,10 +132,14 @@
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 @@
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 @@
sp<NativeHandle> sidebandStream;
mat4 colorTransform;
- bool hasListenerCallbacks;
#ifndef NO_INPUT
InputWindowInfo inputInfo;
#endif
@@ -203,10 +216,30 @@
// 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 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 @@
// 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 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 @@
};
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 @@
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 a5641b0..49c83da 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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
// 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 @@
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 9d96485..adcb898 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 @@
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 transactional state of given display.
+ static status_t getDisplayState(const sp<IBinder>& display, ui::DisplayState*);
- // Get the DisplayInfo for the currently-active configuration
- static status_t getDisplayInfo(const sp<IBinder>& display,
- DisplayInfo* info);
+ // Get immutable information about given physical display.
+ static status_t getDisplayInfo(const sp<IBinder>& display, DisplayInfo*);
- // Get the index of the current active configuration (relative to the list
- // returned by getDisplayInfo)
+ // Get configurations supported by given physical display.
+ static status_t getDisplayConfigs(const sp<IBinder>& display, Vector<DisplayConfig>*);
+
+ // Get the ID of the active DisplayConfig, as getDisplayConfigs index.
static int getActiveConfig(const sp<IBinder>& display);
- // 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);
+ // Shorthand for getDisplayConfigs element at getActiveConfig index.
+ static status_t getActiveDisplayConfig(const sp<IBinder>& display, 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);
-
- // 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);
+ // 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 @@
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 @@
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 @@
*/
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 @@
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 @@
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 @@
}
};
+ 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
* 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 @@
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 @@
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 @@
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 @@
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 23bfc02..ac2bbcc 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -44,7 +44,7 @@
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 @@
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 @@
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 @@
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 627845c..811dcbe 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 @@
*/
/**
- * \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 211fdd5..cda5103 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 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 029dcc0..004d875 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::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 51dff5b..197db26 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 @@
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 1c58167..16d054b 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_vec;
using ::android::hardware::graphics::common::V1_2::HardwareBuffer;
+struct Obituary;
class B2HGraphicBufferProducer : public HGraphicBufferProducer {
public:
@@ -108,6 +109,7 @@
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 898920b..92650b7 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 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 0000000..98f24c2
--- /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 0000000..c98f39f
--- /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/tests/DummyConsumer.h b/libs/gui/mock/GraphicBufferConsumer.cpp
similarity index 66%
copy from libs/gui/tests/DummyConsumer.h
copy to libs/gui/mock/GraphicBufferConsumer.cpp
index 502bdf9..4a6c081 100644
--- a/libs/gui/tests/DummyConsumer.h
+++ b/libs/gui/mock/GraphicBufferConsumer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 The Android Open Source Project
+ * 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.
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-#include <gui/IConsumerListener.h>
+#include <gui/mock/GraphicBufferConsumer.h>
namespace android {
+namespace mock {
-struct DummyConsumer : public BnConsumerListener {
- void onFrameAvailable(const BufferItem& /* item */) override {}
- void onBuffersReleased() override {}
- void onSidebandStreamChanged() override {}
-};
+// Explicit default instantiation is recommended.
+GraphicBufferConsumer::GraphicBufferConsumer() = default;
+GraphicBufferConsumer::~GraphicBufferConsumer() = default;
-} // namespace android
+} // namespace mock
+} // namespace android
\ No newline at end of file
diff --git a/libs/gui/tests/DummyConsumer.h b/libs/gui/mock/GraphicBufferProducer.cpp
similarity index 66%
copy from libs/gui/tests/DummyConsumer.h
copy to libs/gui/mock/GraphicBufferProducer.cpp
index 502bdf9..239a80a 100644
--- a/libs/gui/tests/DummyConsumer.h
+++ b/libs/gui/mock/GraphicBufferProducer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 The Android Open Source Project
+ * 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.
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-#include <gui/IConsumerListener.h>
+#include <gui/mock/GraphicBufferProducer.h>
namespace android {
+namespace mock {
-struct DummyConsumer : public BnConsumerListener {
- void onFrameAvailable(const BufferItem& /* item */) override {}
- void onBuffersReleased() override {}
- void onSidebandStreamChanged() override {}
-};
+// Explicit default instantiation is recommended.
+GraphicBufferProducer::GraphicBufferProducer() = default;
+GraphicBufferProducer::~GraphicBufferProducer() = default;
-} // namespace android
+} // 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 cbda6b2..a6bcd10 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -13,7 +13,8 @@
],
srcs: [
- "BufferItemConsumer_test.cpp",
+ "BLASTBufferQueue_test.cpp",
+ "BufferItemConsumer_test.cpp",
"BufferQueue_test.cpp",
"CpuConsumer_test.cpp",
"EndToEndNativeInputTest.cpp",
@@ -38,6 +39,7 @@
shared_libs: [
"android.hardware.configstore@1.0",
"android.hardware.configstore-utils",
+ "libSurfaceFlingerProp",
"libbase",
"liblog",
"libEGL",
@@ -52,6 +54,8 @@
"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 c02e020..5e09fff 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 0000000..da5bbdd
--- /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 b87cbbd..fc6551c 100644
--- a/libs/gui/tests/BufferItemConsumer_test.cpp
+++ b/libs/gui/tests/BufferItemConsumer_test.cpp
@@ -51,7 +51,7 @@
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 @@
// 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 406f21f..d1208ee 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 @@
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 @@
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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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 @@
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, 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, 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, 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 03b9cd7..b1d3ecb 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 @@
mSurfaceControl = sc;
InputChannel::openInputChannelPair("testchannels", mServerChannel, mClientChannel);
- mServerChannel->setToken(new BBinder());
mInputFlinger = getInputFlinger();
mInputFlinger->registerInputChannel(mServerChannel);
@@ -83,7 +82,8 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
t.setTransparentRegionHint(sc, transparentRegion);
});
surface->showAt(100, 100);
+ surface->assertFocusChange(true);
injectTap(101, 101);
surface->expectTap(1, 1);
}
@@ -415,7 +465,10 @@
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 @@
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 @@
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 @@
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_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 aef7aed..15bd32d 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 @@
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 @@
}
// 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 @@
}
private: // hide from test body
- sp<DummyConsumer> mDC;
+ sp<MockConsumer> mMC;
protected: // accessible from test body
sp<IGraphicBufferProducer> mProducer;
@@ -543,7 +543,6 @@
// 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 acd4297..58d7cc6 100644
--- a/libs/gui/tests/Malicious.cpp
+++ b/libs/gui/tests/Malicious.cpp
@@ -129,7 +129,7 @@
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<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
similarity index 94%
rename from libs/gui/tests/DummyConsumer.h
rename to libs/gui/tests/MockConsumer.h
index 502bdf9..4a6c51c 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 d33ecfb..6746b0a 100644
--- a/libs/gui/tests/RegionSampling_test.cpp
+++ b/libs/gui/tests/RegionSampling_test.cpp
@@ -183,7 +183,7 @@
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 @@
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 @@
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 9891587..5c1bebb 100644
--- a/libs/gui/tests/SamplingDemo.cpp
+++ b/libs/gui/tests/SamplingDemo.cpp
@@ -39,7 +39,7 @@
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 @@
.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 @@
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 ad6e051..b65cdda 100644
--- a/libs/gui/tests/StreamSplitter_test.cpp
+++ b/libs/gui/tests/StreamSplitter_test.cpp
@@ -48,7 +48,7 @@
}
};
-struct DummyListener : public BnConsumerListener {
+struct FakeListener : public BnConsumerListener {
virtual void onFrameAvailable(const BufferItem& /* item */) {}
virtual void onBuffersReleased() {}
virtual void onSidebandStreamChanged() {}
@@ -64,7 +64,7 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 65e09f2..c7458a3 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 @@
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 a851687..592913c 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 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
}
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 @@
return NO_ERROR;
}
status_t setDisplayBrightness(const sp<IBinder>& /*displayToken*/,
- float /*brightness*/) const override {
+ float /*brightness*/) override {
return NO_ERROR;
}
@@ -822,16 +833,37 @@
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 @@
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