diff options
32 files changed, 573 insertions, 306 deletions
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 4ff69c57ce..c94c6b31c6 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -1007,14 +1007,6 @@ status_t BufferQueueProducer::queueBuffer(int slot, mCallbackCondition.notify_all(); } - // Wait without lock held - if (connectedApi == NATIVE_WINDOW_API_EGL) { - // Waiting here allows for two full buffers to be queued but not a - // third. In the event that frames take varying time, this makes a - // small trade-off in favor of latency rather than throughput. - lastQueuedFence->waitForever("Throttling EGL Production"); - } - // Update and get FrameEventHistory. nsecs_t postedTime = systemTime(SYSTEM_TIME_MONOTONIC); NewFrameEventsEntry newFrameEventsEntry = { @@ -1026,6 +1018,14 @@ status_t BufferQueueProducer::queueBuffer(int slot, addAndGetFrameTimestamps(&newFrameEventsEntry, getFrameTimestamps ? &output->frameTimestamps : nullptr); + // Wait without lock held + if (connectedApi == NATIVE_WINDOW_API_EGL) { + // Waiting here allows for two full buffers to be queued but not a + // third. In the event that frames take varying time, this makes a + // small trade-off in favor of latency rather than throughput. + lastQueuedFence->waitForever("Throttling EGL Production"); + } + return NO_ERROR; } diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index a3165ddb9e..a8b1a4c7af 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -69,7 +69,7 @@ public: const sp<IBinder>& applyToken, const InputWindowCommands& commands, int64_t desiredPresentTime, - const cached_buffer_t& uncacheBuffer, + const client_cache_t& uncacheBuffer, const std::vector<ListenerCallbacks>& listenerCallbacks) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); @@ -88,8 +88,8 @@ public: data.writeStrongBinder(applyToken); commands.write(data); data.writeInt64(desiredPresentTime); - data.writeStrongBinder(uncacheBuffer.token); - data.writeUint64(uncacheBuffer.cacheId); + data.writeWeakBinder(uncacheBuffer.token); + data.writeUint64(uncacheBuffer.id); if (data.writeVectorSize(listenerCallbacks) == NO_ERROR) { for (const auto& [listener, callbackIds] : listenerCallbacks) { @@ -991,9 +991,9 @@ status_t BnSurfaceComposer::onTransact( int64_t desiredPresentTime = data.readInt64(); - cached_buffer_t uncachedBuffer; - uncachedBuffer.token = data.readStrongBinder(); - uncachedBuffer.cacheId = data.readUint64(); + client_cache_t uncachedBuffer; + uncachedBuffer.token = data.readWeakBinder(); + uncachedBuffer.id = data.readUint64(); std::vector<ListenerCallbacks> listenerCallbacks; int32_t listenersSize = data.readInt32(); diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 3077b21da7..075bb52e3c 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -87,8 +87,8 @@ status_t layer_state_t::write(Parcel& output) const colorTransform.asArray(), 16 * sizeof(float)); output.writeFloat(cornerRadius); output.writeBool(hasListenerCallbacks); - output.writeStrongBinder(cachedBuffer.token); - output.writeUint64(cachedBuffer.cacheId); + output.writeWeakBinder(cachedBuffer.token); + output.writeUint64(cachedBuffer.id); output.writeParcelable(metadata); output.writeFloat(bgColorAlpha); @@ -157,8 +157,8 @@ status_t layer_state_t::read(const Parcel& input) colorTransform = mat4(static_cast<const float*>(input.readInplace(16 * sizeof(float)))); cornerRadius = input.readFloat(); hasListenerCallbacks = input.readBool(); - cachedBuffer.token = input.readStrongBinder(); - cachedBuffer.cacheId = input.readUint64(); + cachedBuffer.token = input.readWeakBinder(); + cachedBuffer.id = input.readUint64(); input.readParcelable(&metadata); bgColorAlpha = input.readFloat(); diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 611da89ef6..2083a2b023 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -381,17 +381,19 @@ void SurfaceComposerClient::doDropReferenceTransaction(const sp<IBinder>& handle s.state.parentHandleForChild = nullptr; composerStates.add(s); - sf->setTransactionState(composerStates, displayStates, 0, nullptr, {}, -1, {}, {}); + sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); + sf->setTransactionState(composerStates, displayStates, 0, applyToken, {}, -1, {}, {}); } void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) { sp<ISurfaceComposer> sf(ComposerService::getComposerService()); - cached_buffer_t uncacheBuffer; + client_cache_t uncacheBuffer; uncacheBuffer.token = BufferCache::getInstance().getToken(); - uncacheBuffer.cacheId = cacheId; + uncacheBuffer.id = cacheId; - sf->setTransactionState({}, {}, 0, nullptr, {}, -1, uncacheBuffer, {}); + sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); + sf->setTransactionState({}, {}, 0, applyToken, {}, -1, uncacheBuffer, {}); } void SurfaceComposerClient::Transaction::cacheBuffers() { @@ -422,7 +424,7 @@ void SurfaceComposerClient::Transaction::cacheBuffers() { } s->what |= layer_state_t::eCachedBufferChanged; s->cachedBuffer.token = BufferCache::getInstance().getToken(); - s->cachedBuffer.cacheId = cacheId; + s->cachedBuffer.id = cacheId; // If we have more buffers than the size of the cache, we should stop caching so we don't // evict other buffers in this transaction diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 415b2d58ec..e8c7a39ad7 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -44,7 +44,7 @@ namespace android { // ---------------------------------------------------------------------------- -struct cached_buffer_t; +struct client_cache_t; struct ComposerState; struct DisplayState; struct DisplayInfo; @@ -137,7 +137,7 @@ public: const sp<IBinder>& applyToken, const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime, - const cached_buffer_t& uncacheBuffer, + const client_cache_t& uncacheBuffer, const std::vector<ListenerCallbacks>& listenerCallbacks) = 0; /* signal that we're done booting. diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 2256497751..f438eb3d01 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -40,9 +40,13 @@ namespace android { class Parcel; class ISurfaceComposerClient; -struct cached_buffer_t { - sp<IBinder> token = nullptr; - uint64_t cacheId; +struct client_cache_t { + wp<IBinder> token = nullptr; + uint64_t id; + + bool operator==(const client_cache_t& other) const { return id == other.id; } + + bool isValid() const { return token != nullptr; } }; /* @@ -187,7 +191,7 @@ struct layer_state_t { InputWindowInfo inputInfo; #endif - cached_buffer_t cachedBuffer; + client_cache_t cachedBuffer; LayerMetadata metadata; diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index d5bdd74a86..014b1fac7d 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -561,8 +561,7 @@ public: const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/, const sp<IBinder>& /*applyToken*/, const InputWindowCommands& /*inputWindowCommands*/, - int64_t /*desiredPresentTime*/, - const cached_buffer_t& /*cachedBuffer*/, + int64_t /*desiredPresentTime*/, const client_cache_t& /*cachedBuffer*/, const std::vector<ListenerCallbacks>& /*listenerCallbacks*/) override { } diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 9080d29194..4cd0a13861 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -116,7 +116,7 @@ filegroup { "BufferLayerConsumer.cpp", "BufferQueueLayer.cpp", "BufferStateLayer.cpp", - "BufferStateLayerCache.cpp", + "ClientCache.cpp", "Client.cpp", "ColorLayer.cpp", "ContainerLayer.cpp", diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 2cbb917478..6ef4518a47 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -26,6 +26,7 @@ #include <compositionengine/OutputLayer.h> #include <compositionengine/impl/LayerCompositionState.h> #include <compositionengine/impl/OutputLayerCompositionState.h> +#include <gui/BufferQueue.h> #include <private/gui/SyncFeatures.h> #include <renderengine/Image.h> @@ -44,7 +45,8 @@ const std::array<float, 16> BufferStateLayer::IDENTITY_MATRIX{ }; // clang-format on -BufferStateLayer::BufferStateLayer(const LayerCreationArgs& args) : BufferLayer(args) { +BufferStateLayer::BufferStateLayer(const LayerCreationArgs& args) + : BufferLayer(args), mHwcSlotGenerator(new HwcSlotGenerator()) { mOverrideScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; mCurrentState.dataspace = ui::Dataspace::V0_SRGB; } @@ -210,12 +212,13 @@ bool BufferStateLayer::setFrame(const Rect& frame) { } bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, nsecs_t postTime, - nsecs_t desiredPresentTime) { + nsecs_t desiredPresentTime, const client_cache_t& clientCacheId) { if (mCurrentState.buffer) { mReleasePreviousBuffer = true; } mCurrentState.buffer = buffer; + mCurrentState.clientCacheId = clientCacheId; mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); @@ -589,8 +592,8 @@ void BufferStateLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) uint32_t hwcSlot; sp<GraphicBuffer> buffer; - hwcInfo.hwcBufferCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, s.buffer, &hwcSlot, - &buffer); + hwcInfo.hwcBufferCache.getHwcBuffer(mHwcSlotGenerator->getHwcCacheSlot(s.clientCacheId), + s.buffer, &hwcSlot, &buffer); auto error = hwcLayer->setBuffer(hwcSlot, buffer, s.acquireFence); if (error != HWC2::Error::None) { @@ -609,4 +612,76 @@ void BufferStateLayer::onFirstRef() { } } +void BufferStateLayer::HwcSlotGenerator::bufferErased(const client_cache_t& clientCacheId) { + std::lock_guard lock(mMutex); + if (!clientCacheId.isValid()) { + ALOGE("invalid process, failed to erase buffer"); + return; + } + eraseBufferLocked(clientCacheId); +} + +uint32_t BufferStateLayer::HwcSlotGenerator::getHwcCacheSlot(const client_cache_t& clientCacheId) { + std::lock_guard<std::mutex> lock(mMutex); + auto itr = mCachedBuffers.find(clientCacheId); + if (itr == mCachedBuffers.end()) { + return addCachedBuffer(clientCacheId); + } + auto& [hwcCacheSlot, counter] = itr->second; + counter = mCounter++; + return hwcCacheSlot; +} + +uint32_t BufferStateLayer::HwcSlotGenerator::addCachedBuffer(const client_cache_t& clientCacheId) + REQUIRES(mMutex) { + if (!clientCacheId.isValid()) { + ALOGE("invalid process, returning invalid slot"); + return BufferQueue::INVALID_BUFFER_SLOT; + } + + ClientCache::getInstance().registerErasedRecipient(clientCacheId, wp<ErasedRecipient>(this)); + + uint32_t hwcCacheSlot = getFreeHwcCacheSlot(); + mCachedBuffers[clientCacheId] = {hwcCacheSlot, mCounter++}; + return hwcCacheSlot; +} + +uint32_t BufferStateLayer::HwcSlotGenerator::getFreeHwcCacheSlot() REQUIRES(mMutex) { + if (mFreeHwcCacheSlots.empty()) { + evictLeastRecentlyUsed(); + } + + uint32_t hwcCacheSlot = mFreeHwcCacheSlots.top(); + mFreeHwcCacheSlots.pop(); + return hwcCacheSlot; +} + +void BufferStateLayer::HwcSlotGenerator::evictLeastRecentlyUsed() REQUIRES(mMutex) { + uint64_t minCounter = UINT_MAX; + client_cache_t minClientCacheId = {}; + for (const auto& [clientCacheId, slotCounter] : mCachedBuffers) { + const auto& [hwcCacheSlot, counter] = slotCounter; + if (counter < minCounter) { + minCounter = counter; + minClientCacheId = clientCacheId; + } + } + eraseBufferLocked(minClientCacheId); + + ClientCache::getInstance().unregisterErasedRecipient(minClientCacheId, this); +} + +void BufferStateLayer::HwcSlotGenerator::eraseBufferLocked(const client_cache_t& clientCacheId) + REQUIRES(mMutex) { + auto itr = mCachedBuffers.find(clientCacheId); + if (itr == mCachedBuffers.end()) { + return; + } + auto& [hwcCacheSlot, counter] = itr->second; + + // TODO send to hwc cache and resources + + mFreeHwcCacheSlots.push(hwcCacheSlot); + mCachedBuffers.erase(clientCacheId); +} } // namespace android diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 864a15db1f..13186dd343 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -25,8 +25,12 @@ #include <system/window.h> #include <utils/String8.h> +#include <stack> + namespace android { +class SlotGenerationTest; + class BufferStateLayer : public BufferLayer { public: explicit BufferStateLayer(const LayerCreationArgs&); @@ -63,8 +67,8 @@ public: bool setTransformToDisplayInverse(bool transformToDisplayInverse) override; bool setCrop(const Rect& crop) override; bool setFrame(const Rect& frame) override; - bool setBuffer(const sp<GraphicBuffer>& buffer, nsecs_t postTime, - nsecs_t desiredPresentTime) override; + bool setBuffer(const sp<GraphicBuffer>& buffer, nsecs_t postTime, nsecs_t desiredPresentTime, + const client_cache_t& clientCacheId) override; bool setAcquireFence(const sp<Fence>& fence) override; bool setDataspace(ui::Dataspace dataspace) override; bool setHdrMetadata(const HdrMetadata& hdrMetadata) override; @@ -132,6 +136,7 @@ private: void setHwcLayerBuffer(const sp<const DisplayDevice>& display) override; private: + friend class SlotGenerationTest; void onFirstRef() override; bool willPresentCurrentTransaction() const; @@ -154,6 +159,46 @@ private: nsecs_t mDesiredPresentTime = -1; // TODO(marissaw): support sticky transform for LEGACY camera mode + + class HwcSlotGenerator : public ClientCache::ErasedRecipient { + public: + HwcSlotGenerator() { + for (uint32_t i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { + mFreeHwcCacheSlots.push(i); + } + } + + void bufferErased(const client_cache_t& clientCacheId); + + uint32_t getHwcCacheSlot(const client_cache_t& clientCacheId); + + private: + friend class SlotGenerationTest; + uint32_t addCachedBuffer(const client_cache_t& clientCacheId) REQUIRES(mMutex); + uint32_t getFreeHwcCacheSlot() REQUIRES(mMutex); + void evictLeastRecentlyUsed() REQUIRES(mMutex); + void eraseBufferLocked(const client_cache_t& clientCacheId) REQUIRES(mMutex); + + struct CachedBufferHash { + std::size_t operator()(const client_cache_t& clientCacheId) const { + return std::hash<uint64_t>{}(clientCacheId.id); + } + }; + + std::mutex mMutex; + + std::unordered_map<client_cache_t, + std::pair<uint32_t /*HwcCacheSlot*/, uint32_t /*counter*/>, + CachedBufferHash> + mCachedBuffers GUARDED_BY(mMutex); + std::stack<uint32_t /*HwcCacheSlot*/> mFreeHwcCacheSlots GUARDED_BY(mMutex); + + // The cache increments this counter value when a slot is updated or used. + // Used to track the least recently-used buffer + uint64_t mCounter = 0; + }; + + sp<HwcSlotGenerator> mHwcSlotGenerator; }; } // namespace android diff --git a/services/surfaceflinger/BufferStateLayerCache.cpp b/services/surfaceflinger/BufferStateLayerCache.cpp deleted file mode 100644 index 51ca45c53a..0000000000 --- a/services/surfaceflinger/BufferStateLayerCache.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 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_NDEBUG 0 -#undef LOG_TAG -#define LOG_TAG "BufferStateLayerCache" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS - -#include <cinttypes> - -#include "BufferStateLayerCache.h" - -namespace android { - -ANDROID_SINGLETON_STATIC_INSTANCE(BufferStateLayerCache); - -BufferStateLayerCache::BufferStateLayerCache() : mDeathRecipient(new CacheDeathRecipient) {} - -void BufferStateLayerCache::add(const sp<IBinder>& processToken, uint64_t id, - const sp<GraphicBuffer>& buffer) { - if (!processToken) { - ALOGE("failed to cache buffer: invalid process token"); - return; - } - - if (!buffer) { - ALOGE("failed to cache buffer: invalid buffer"); - return; - } - - std::lock_guard lock(mMutex); - - // If this is a new process token, set a death recipient. If the client process dies, we will - // get a callback through binderDied. - if (mBuffers.find(processToken) == mBuffers.end()) { - status_t err = processToken->linkToDeath(mDeathRecipient); - if (err != NO_ERROR) { - ALOGE("failed to cache buffer: could not link to death"); - return; - } - } - - auto& processBuffers = mBuffers[processToken]; - - if (processBuffers.size() > BUFFER_CACHE_MAX_SIZE) { - ALOGE("failed to cache buffer: cache is full"); - return; - } - - processBuffers[id] = buffer; -} - -void BufferStateLayerCache::erase(const sp<IBinder>& processToken, uint64_t id) { - if (!processToken) { - ALOGE("failed to uncache buffer: invalid process token"); - return; - } - - std::lock_guard lock(mMutex); - - if (mBuffers.find(processToken) == mBuffers.end()) { - ALOGE("failed to uncache buffer: process token not found"); - return; - } - - auto& processBuffers = mBuffers[processToken]; - processBuffers.erase(id); -} - -sp<GraphicBuffer> BufferStateLayerCache::get(const sp<IBinder>& processToken, uint64_t id) { - if (!processToken) { - ALOGE("failed to cache buffer: invalid process token"); - return nullptr; - } - - std::lock_guard lock(mMutex); - auto itr = mBuffers.find(processToken); - if (itr == mBuffers.end()) { - ALOGE("failed to get buffer: process token not found"); - return nullptr; - } - - if (itr->second.find(id) == itr->second.end()) { - ALOGE("failed to get buffer: buffer not found"); - return nullptr; - } - - return itr->second[id]; -} - -void BufferStateLayerCache::removeProcess(const wp<IBinder>& processToken) { - std::lock_guard lock(mMutex); - mBuffers.erase(processToken); -} - -void BufferStateLayerCache::CacheDeathRecipient::binderDied(const wp<IBinder>& who) { - BufferStateLayerCache::getInstance().removeProcess(who); -} - -}; // namespace android diff --git a/services/surfaceflinger/ClientCache.cpp b/services/surfaceflinger/ClientCache.cpp new file mode 100644 index 0000000000..77f2f5765c --- /dev/null +++ b/services/surfaceflinger/ClientCache.cpp @@ -0,0 +1,202 @@ +/* + * Copyright 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_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "ClientCache" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include <cinttypes> + +#include "ClientCache.h" + +namespace android { + +ANDROID_SINGLETON_STATIC_INSTANCE(ClientCache); + +ClientCache::ClientCache() : mDeathRecipient(new CacheDeathRecipient) {} + +bool ClientCache::getBuffer(const client_cache_t& cacheId, + ClientCacheBuffer** outClientCacheBuffer) { + auto& [processToken, id] = cacheId; + if (processToken == nullptr) { + ALOGE("failed to get buffer, invalid (nullptr) process token"); + return false; + } + auto it = mBuffers.find(processToken); + if (it == mBuffers.end()) { + ALOGE("failed to get buffer, invalid process token"); + return false; + } + + auto& processBuffers = it->second; + + auto bufItr = processBuffers.find(id); + if (bufItr == processBuffers.end()) { + ALOGE("failed to get buffer, invalid buffer id"); + return false; + } + + ClientCacheBuffer& buf = bufItr->second; + *outClientCacheBuffer = &buf; + return true; +} + +void ClientCache::add(const client_cache_t& cacheId, const sp<GraphicBuffer>& buffer) { + auto& [processToken, id] = cacheId; + if (processToken == nullptr) { + ALOGE("failed to cache buffer: invalid process token"); + return; + } + + if (!buffer) { + ALOGE("failed to cache buffer: invalid buffer"); + return; + } + + std::lock_guard lock(mMutex); + sp<IBinder> token; + + // If this is a new process token, set a death recipient. If the client process dies, we will + // get a callback through binderDied. + auto it = mBuffers.find(processToken); + if (it == mBuffers.end()) { + token = processToken.promote(); + if (!token) { + ALOGE("failed to cache buffer: invalid token"); + return; + } + + status_t err = token->linkToDeath(mDeathRecipient); + if (err != NO_ERROR) { + ALOGE("failed to cache buffer: could not link to death"); + return; + } + auto [itr, success] = + mBuffers.emplace(processToken, std::unordered_map<uint64_t, ClientCacheBuffer>()); + LOG_ALWAYS_FATAL_IF(!success, "failed to insert new process into client cache"); + it = itr; + } + + auto& processBuffers = it->second; + + if (processBuffers.size() > BUFFER_CACHE_MAX_SIZE) { + ALOGE("failed to cache buffer: cache is full"); + return; + } + + processBuffers[id].buffer = buffer; +} + +void ClientCache::erase(const client_cache_t& cacheId) { + auto& [processToken, id] = cacheId; + std::vector<sp<ErasedRecipient>> pendingErase; + { + std::lock_guard lock(mMutex); + ClientCacheBuffer* buf = nullptr; + if (!getBuffer(cacheId, &buf)) { + ALOGE("failed to erase buffer, could not retrieve buffer"); + return; + } + + for (auto& recipient : buf->recipients) { + sp<ErasedRecipient> erasedRecipient = recipient.promote(); + if (erasedRecipient) { + pendingErase.push_back(erasedRecipient); + } + } + + mBuffers[processToken].erase(id); + } + + for (auto& recipient : pendingErase) { + recipient->bufferErased(cacheId); + } +} + +sp<GraphicBuffer> ClientCache::get(const client_cache_t& cacheId) { + std::lock_guard lock(mMutex); + + ClientCacheBuffer* buf = nullptr; + if (!getBuffer(cacheId, &buf)) { + ALOGE("failed to get buffer, could not retrieve buffer"); + return nullptr; + } + + return buf->buffer; +} + +void ClientCache::registerErasedRecipient(const client_cache_t& cacheId, + const wp<ErasedRecipient>& recipient) { + std::lock_guard lock(mMutex); + + ClientCacheBuffer* buf = nullptr; + if (!getBuffer(cacheId, &buf)) { + ALOGE("failed to register erased recipient, could not retrieve buffer"); + return; + } + buf->recipients.insert(recipient); +} + +void ClientCache::unregisterErasedRecipient(const client_cache_t& cacheId, + const wp<ErasedRecipient>& recipient) { + std::lock_guard lock(mMutex); + + ClientCacheBuffer* buf = nullptr; + if (!getBuffer(cacheId, &buf)) { + ALOGE("failed to unregister erased recipient"); + return; + } + + buf->recipients.erase(recipient); +} + +void ClientCache::removeProcess(const wp<IBinder>& processToken) { + std::vector<std::pair<sp<ErasedRecipient>, client_cache_t>> pendingErase; + { + if (processToken == nullptr) { + ALOGE("failed to remove process, invalid (nullptr) process token"); + return; + } + std::lock_guard lock(mMutex); + auto itr = mBuffers.find(processToken); + if (itr == mBuffers.end()) { + ALOGE("failed to remove process, could not find process"); + return; + } + + for (auto& [id, clientCacheBuffer] : itr->second) { + client_cache_t cacheId = {processToken, id}; + for (auto& recipient : clientCacheBuffer.recipients) { + sp<ErasedRecipient> erasedRecipient = recipient.promote(); + if (erasedRecipient) { + pendingErase.emplace_back(erasedRecipient, cacheId); + } + } + } + mBuffers.erase(itr); + } + + for (auto& [recipient, cacheId] : pendingErase) { + recipient->bufferErased(cacheId); + } +} + +void ClientCache::CacheDeathRecipient::binderDied(const wp<IBinder>& who) { + ClientCache::getInstance().removeProcess(who); +} + +}; // namespace android diff --git a/services/surfaceflinger/BufferStateLayerCache.h b/services/surfaceflinger/ClientCache.h index 415c09cf96..9f057c45d4 100644 --- a/services/surfaceflinger/BufferStateLayerCache.h +++ b/services/surfaceflinger/ClientCache.h @@ -18,32 +18,50 @@ #include <android-base/thread_annotations.h> #include <binder/IBinder.h> +#include <gui/LayerState.h> #include <ui/GraphicBuffer.h> #include <utils/RefBase.h> #include <utils/Singleton.h> -#include <array> #include <map> #include <mutex> +#include <set> +#include <unordered_map> #define BUFFER_CACHE_MAX_SIZE 64 namespace android { -class BufferStateLayerCache : public Singleton<BufferStateLayerCache> { +class ClientCache : public Singleton<ClientCache> { public: - BufferStateLayerCache(); + ClientCache(); - void add(const sp<IBinder>& processToken, uint64_t id, const sp<GraphicBuffer>& buffer); - void erase(const sp<IBinder>& processToken, uint64_t id); + void add(const client_cache_t& cacheId, const sp<GraphicBuffer>& buffer); + void erase(const client_cache_t& cacheId); - sp<GraphicBuffer> get(const sp<IBinder>& processToken, uint64_t id); + sp<GraphicBuffer> get(const client_cache_t& cacheId); void removeProcess(const wp<IBinder>& processToken); + class ErasedRecipient : public virtual RefBase { + public: + virtual void bufferErased(const client_cache_t& clientCacheId) = 0; + }; + + void registerErasedRecipient(const client_cache_t& cacheId, + const wp<ErasedRecipient>& recipient); + void unregisterErasedRecipient(const client_cache_t& cacheId, + const wp<ErasedRecipient>& recipient); + private: std::mutex mMutex; - std::map<wp<IBinder> /*caching process*/, std::map<uint64_t /*Cache id*/, sp<GraphicBuffer>>> + + struct ClientCacheBuffer { + sp<GraphicBuffer> buffer; + std::set<wp<ErasedRecipient>> recipients; + }; + std::map<wp<IBinder> /*caching process*/, + std::unordered_map<uint64_t /*cache id*/, ClientCacheBuffer>> mBuffers GUARDED_BY(mMutex); class CacheDeathRecipient : public IBinder::DeathRecipient { @@ -52,6 +70,9 @@ private: }; sp<CacheDeathRecipient> mDeathRecipient; + + bool getBuffer(const client_cache_t& cacheId, ClientCacheBuffer** outClientCacheBuffer) + REQUIRES(mMutex); }; }; // namespace android diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h index 97bdc8ff67..8eec035bd9 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h @@ -48,20 +48,11 @@ public: void getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot, sp<GraphicBuffer>* outBuffer); -protected: - bool getSlot(const sp<GraphicBuffer>& buffer, uint32_t* outSlot); - uint32_t getLeastRecentlyUsedSlot(); - uint64_t getCounter(); - private: // an array where the index corresponds to a slot and the value corresponds to a (counter, // buffer) pair. "counter" is a unique value that indicates the last time this slot was updated // or used and allows us to keep track of the least-recently used buffer. - std::pair<uint64_t, wp<GraphicBuffer>> mBuffers[BufferQueue::NUM_BUFFER_SLOTS]; - - // The cache increments this counter value when a slot is updated or used. - // Used to track the least recently-used buffer - uint64_t mCounter = 1; + wp<GraphicBuffer> mBuffers[BufferQueue::NUM_BUFFER_SLOTS]; }; } // namespace compositionengine::impl diff --git a/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp index a941e0962d..f72862be07 100644 --- a/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp +++ b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp @@ -21,60 +21,30 @@ namespace android::compositionengine::impl { HwcBufferCache::HwcBufferCache() { - std::fill(std::begin(mBuffers), std::end(mBuffers), - std::pair<uint64_t, wp<GraphicBuffer>>(0, nullptr)); -} -bool HwcBufferCache::getSlot(const sp<GraphicBuffer>& buffer, uint32_t* outSlot) { - // search for cached buffer first - for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { - // Weak pointers in the cache may have had their object destroyed. - // Comparisons between weak pointers will accurately reflect this case, - // but comparisons between weak and strong may not. Thus, we create a weak - // pointer from strong pointer buffer - wp<GraphicBuffer> weakCopy(buffer); - if (mBuffers[i].second == weakCopy) { - *outSlot = i; - return true; - } - } - - // use the least-recently used slot - *outSlot = getLeastRecentlyUsedSlot(); - return false; -} - -uint32_t HwcBufferCache::getLeastRecentlyUsedSlot() { - auto iter = std::min_element(std::begin(mBuffers), std::end(mBuffers)); - return std::distance(std::begin(mBuffers), iter); + std::fill(std::begin(mBuffers), std::end(mBuffers), wp<GraphicBuffer>(nullptr)); } void HwcBufferCache::getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot, sp<GraphicBuffer>* outBuffer) { - // if this slot corresponds to a BufferStateLayer, generate the slot - if (slot == BufferQueue::INVALID_BUFFER_SLOT) { - getSlot(buffer, outSlot); - } else if (slot < 0 || slot >= BufferQueue::NUM_BUFFER_SLOTS) { + // default is 0 + if (slot == BufferQueue::INVALID_BUFFER_SLOT || slot < 0 || + slot >= BufferQueue::NUM_BUFFER_SLOTS) { *outSlot = 0; } else { *outSlot = slot; } - auto& [currentCounter, currentBuffer] = mBuffers[*outSlot]; + auto& currentBuffer = mBuffers[*outSlot]; wp<GraphicBuffer> weakCopy(buffer); if (currentBuffer == weakCopy) { // already cached in HWC, skip sending the buffer *outBuffer = nullptr; - currentCounter = getCounter(); } else { *outBuffer = buffer; // update cache currentBuffer = buffer; - currentCounter = getCounter(); } } -uint64_t HwcBufferCache::getCounter() { - return mCounter++; -} } // namespace android::compositionengine::impl diff --git a/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp b/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp index b261493a20..00eafb15f5 100644 --- a/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp @@ -28,10 +28,6 @@ public: sp<GraphicBuffer>* outBuffer) { HwcBufferCache::getHwcBuffer(slot, buffer, outSlot, outBuffer); } - bool getSlot(const sp<GraphicBuffer>& buffer, uint32_t* outSlot) { - return HwcBufferCache::getSlot(buffer, outSlot); - } - uint32_t getLeastRecentlyUsedSlot() { return HwcBufferCache::getLeastRecentlyUsedSlot(); } }; class HwcBufferCacheTest : public testing::Test { @@ -86,41 +82,5 @@ TEST_F(HwcBufferCacheTest, cacheMapsNegativeSlotToZero) { testSlot(-123, 0); } -TEST_F(HwcBufferCacheTest, cacheGeneratesSlotForInvalidBufferSlot) { - uint32_t outSlot; - sp<GraphicBuffer> outBuffer; - - mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer1, &outSlot, &outBuffer); - EXPECT_EQ(0, outSlot); - EXPECT_EQ(mBuffer1, outBuffer); - - mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer1, &outSlot, &outBuffer); - EXPECT_EQ(0, outSlot); - EXPECT_EQ(nullptr, outBuffer.get()); - - mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer2, &outSlot, &outBuffer); - EXPECT_EQ(1, outSlot); - EXPECT_EQ(mBuffer2, outBuffer); - - mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer2, &outSlot, &outBuffer); - EXPECT_EQ(1, outSlot); - EXPECT_EQ(nullptr, outBuffer.get()); - - mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, sp<GraphicBuffer>(), &outSlot, - &outBuffer); - EXPECT_EQ(2, outSlot); - EXPECT_EQ(nullptr, outBuffer.get()); - - // note that sending mBuffer1 with explicit slot 1 will overwrite mBuffer2 - // and also cause mBuffer1 to be stored in two places - mCache.getHwcBuffer(1, mBuffer1, &outSlot, &outBuffer); - EXPECT_EQ(1, outSlot); - EXPECT_EQ(mBuffer1, outBuffer); - - mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer2, &outSlot, &outBuffer); - EXPECT_EQ(3, outSlot); - EXPECT_EQ(mBuffer2, outBuffer); -} - } // namespace } // namespace android::compositionengine diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp index 9cb43bccfa..cc5a5b5729 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp @@ -1158,23 +1158,6 @@ Error Composer::setLayerPerFrameMetadataBlobs( return Error::NONE; } -Error Composer::getDisplayBrightnessSupport(Display display, bool* outSupport) { - if (!mClient_2_3) { - return Error::UNSUPPORTED; - } - Error error = kDefaultError; - mClient_2_3->getDisplayBrightnessSupport(display, - [&](const auto& tmpError, const auto& tmpSupport) { - error = tmpError; - if (error != Error::NONE) { - return; - } - - *outSupport = tmpSupport; - }); - return error; -} - Error Composer::setDisplayBrightness(Display display, float brightness) { if (!mClient_2_3) { return Error::UNSUPPORTED; diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index e24db152e9..c4e952b8d9 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -203,7 +203,6 @@ public: std::vector<DisplayCapability>* outCapabilities) = 0; virtual Error setLayerPerFrameMetadataBlobs( Display display, Layer layer, const std::vector<PerFrameMetadataBlob>& metadata) = 0; - virtual Error getDisplayBrightnessSupport(Display display, bool* outSupport) = 0; virtual Error setDisplayBrightness(Display display, float brightness) = 0; }; @@ -416,7 +415,6 @@ public: Error setLayerPerFrameMetadataBlobs( Display display, Layer layer, const std::vector<IComposerClient::PerFrameMetadataBlob>& metadata) override; - Error getDisplayBrightnessSupport(Display display, bool* outSupport) override; Error setDisplayBrightness(Display display, float brightness) override; private: diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index 12a94a70d6..9690605b6f 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -276,11 +276,6 @@ Display::Display(android::Hwc2::Composer& composer, if (error == Error::None && dozeSupport) { mDisplayCapabilities.emplace(DisplayCapability::Doze); } - bool brightnessSupport = false; - error = static_cast<Error>(mComposer.getDisplayBrightnessSupport(mId, &brightnessSupport)); - if (error == Error::None && brightnessSupport) { - mDisplayCapabilities.emplace(DisplayCapability::Brightness); - } } ALOGV("Created display %" PRIu64, id); } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 1527c34122..b6323a245d 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1898,6 +1898,7 @@ void Layer::writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet, layerInfo->set_is_opaque(isOpaque(state)); layerInfo->set_invalidate(contentDirty); + layerInfo->set_is_protected(isProtected()); // XXX (b/79210409) mCurrentDataSpace is not protected layerInfo->set_dataspace( diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index f4545e0538..c76394cf31 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -199,6 +199,7 @@ public: Region transparentRegionHint; sp<GraphicBuffer> buffer; + client_cache_t clientCacheId; sp<Fence> acquireFence; HdrMetadata hdrMetadata; Region surfaceDamageRegion; @@ -312,9 +313,10 @@ public: virtual bool setCrop(const Rect& /*crop*/) { return false; }; virtual bool setFrame(const Rect& /*frame*/) { return false; }; virtual bool setBuffer(const sp<GraphicBuffer>& /*buffer*/, nsecs_t /*postTime*/, - nsecs_t /*desiredPresentTime*/) { + nsecs_t /*desiredPresentTime*/, + const client_cache_t& /*clientCacheId*/) { return false; - } + }; virtual bool setAcquireFence(const sp<Fence>& /*fence*/) { return false; }; virtual bool setDataspace(ui::Dataspace /*dataspace*/) { return false; }; virtual bool setHdrMetadata(const HdrMetadata& /*hdrMetadata*/) { return false; }; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 606355549e..3744f8b0b8 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -75,7 +75,6 @@ #include "BufferLayer.h" #include "BufferQueueLayer.h" #include "BufferStateLayer.h" -#include "BufferStateLayerCache.h" #include "Client.h" #include "ColorLayer.h" #include "Colorizer.h" @@ -2195,8 +2194,9 @@ void SurfaceFlinger::rebuildLayerStacks() { // - Dataspace::UNKNOWN // - Dataspace::BT2020_HLG // - Dataspace::BT2020_PQ -Dataspace SurfaceFlinger::getBestDataspace(const sp<const DisplayDevice>& display, - Dataspace* outHdrDataSpace) const { +Dataspace SurfaceFlinger::getBestDataspace(const sp<DisplayDevice>& display, + Dataspace* outHdrDataSpace, + bool* outIsHdrClientComposition) const { Dataspace bestDataSpace = Dataspace::V0_SRGB; *outHdrDataSpace = Dataspace::UNKNOWN; @@ -2217,6 +2217,7 @@ Dataspace SurfaceFlinger::getBestDataspace(const sp<const DisplayDevice>& displa case Dataspace::BT2020_ITU_PQ: bestDataSpace = Dataspace::DISPLAY_P3; *outHdrDataSpace = Dataspace::BT2020_PQ; + *outIsHdrClientComposition = layer->getForceClientComposition(display); break; case Dataspace::BT2020_HLG: case Dataspace::BT2020_ITU_HLG: @@ -2246,7 +2247,8 @@ void SurfaceFlinger::pickColorMode(const sp<DisplayDevice>& display, ColorMode* } Dataspace hdrDataSpace; - Dataspace bestDataSpace = getBestDataspace(display, &hdrDataSpace); + bool isHdrClientComposition = false; + Dataspace bestDataSpace = getBestDataspace(display, &hdrDataSpace, &isHdrClientComposition); auto* profile = display->getCompositionDisplay()->getDisplayColorProfile(); @@ -2262,8 +2264,8 @@ void SurfaceFlinger::pickColorMode(const sp<DisplayDevice>& display, ColorMode* } // respect hdrDataSpace only when there is no legacy HDR support - const bool isHdr = - hdrDataSpace != Dataspace::UNKNOWN && !profile->hasLegacyHdrSupport(hdrDataSpace); + const bool isHdr = hdrDataSpace != Dataspace::UNKNOWN && + !profile->hasLegacyHdrSupport(hdrDataSpace) && !isHdrClientComposition; if (isHdr) { bestDataSpace = hdrDataSpace; } @@ -2881,7 +2883,7 @@ void SurfaceFlinger::updateInputWindowInfo() { } void SurfaceFlinger::commitInputWindowCommands() { - mInputWindowCommands.merge(mPendingInputWindowCommands); + mInputWindowCommands = mPendingInputWindowCommands; mPendingInputWindowCommands.clear(); } @@ -3542,7 +3544,7 @@ void SurfaceFlinger::setTransactionState(const Vector<ComposerState>& states, const sp<IBinder>& applyToken, const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime, - const cached_buffer_t& uncacheBuffer, + const client_cache_t& uncacheBuffer, const std::vector<ListenerCallbacks>& listenerCallbacks) { ATRACE_CALL(); @@ -3574,7 +3576,7 @@ void SurfaceFlinger::applyTransactionState(const Vector<ComposerState>& states, const Vector<DisplayState>& displays, uint32_t flags, const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime, - const cached_buffer_t& uncacheBuffer, + const client_cache_t& uncacheBuffer, const std::vector<ListenerCallbacks>& listenerCallbacks, const int64_t postTime, bool privileged, bool isMainThread) { @@ -3583,7 +3585,7 @@ void SurfaceFlinger::applyTransactionState(const Vector<ComposerState>& states, if (flags & eAnimation) { // For window updates that are part of an animation we must wait for // previous animation "frames" to be handled. - while (mAnimTransactionPending) { + while (!isMainThread && mAnimTransactionPending) { status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5)); if (CC_UNLIKELY(err != NO_ERROR)) { // just in case something goes wrong in SF, return to the @@ -3617,15 +3619,15 @@ void SurfaceFlinger::applyTransactionState(const Vector<ComposerState>& states, } // If the state doesn't require a traversal and there are callbacks, send them now - if (!(clientStateFlags & eTraversalNeeded)) { + if (!(clientStateFlags & eTraversalNeeded) && !listenerCallbacks.empty()) { mTransactionCompletedThread.sendCallbacks(); } transactionFlags |= clientStateFlags; transactionFlags |= addInputWindowCommands(inputWindowCommands); - if (uncacheBuffer.token) { - BufferStateLayerCache::getInstance().erase(uncacheBuffer.token, uncacheBuffer.cacheId); + if (uncacheBuffer.isValid()) { + ClientCache::getInstance().erase(uncacheBuffer); } // If a synchronous transaction is explicitly requested without any changes, force a transaction @@ -3662,8 +3664,9 @@ void SurfaceFlinger::applyTransactionState(const Vector<ComposerState>& states, if (flags & eAnimation) { mAnimTransactionPending = true; } - - mPendingSyncInputWindows = mPendingInputWindowCommands.syncInputWindows; + if (mPendingInputWindowCommands.syncInputWindows) { + mPendingSyncInputWindows = true; + } // applyTransactionState can be called by either the main SF thread or by // another process through setTransactionState. While a given process may wish @@ -3980,17 +3983,15 @@ uint32_t SurfaceFlinger::setClientStateLocked( bool cacheIdChanged = what & layer_state_t::eCachedBufferChanged; sp<GraphicBuffer> buffer; if (bufferChanged && cacheIdChanged) { - BufferStateLayerCache::getInstance().add(s.cachedBuffer.token, s.cachedBuffer.cacheId, - s.buffer); + ClientCache::getInstance().add(s.cachedBuffer, s.buffer); buffer = s.buffer; } else if (cacheIdChanged) { - buffer = BufferStateLayerCache::getInstance().get(s.cachedBuffer.token, - s.cachedBuffer.cacheId); + buffer = ClientCache::getInstance().get(s.cachedBuffer); } else if (bufferChanged) { buffer = s.buffer; } if (buffer) { - if (layer->setBuffer(buffer, postTime, desiredPresentTime)) { + if (layer->setBuffer(buffer, postTime, desiredPresentTime, s.cachedBuffer)) { flags |= eTraversalNeeded; } } @@ -5872,12 +5873,15 @@ status_t SurfaceFlinger::getAllowedDisplayConfigs(const sp<IBinder>& displayToke Mutex::Autolock lock(mStateLock); - if (displayToken != getInternalDisplayTokenLocked()) { - ALOGE("%s is only supported for the internal display", __FUNCTION__); + const auto display = getDisplayDeviceLocked(displayToken); + if (!display) { return NAME_NOT_FOUND; } - outAllowedConfigs->assign(mAllowedDisplayConfigs.begin(), mAllowedDisplayConfigs.end()); + if (display->isPrimary()) { + outAllowedConfigs->assign(mAllowedDisplayConfigs.begin(), mAllowedDisplayConfigs.end()); + } + return NO_ERROR; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 7a7ad33d67..13b2182202 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -46,6 +46,7 @@ #include <utils/Trace.h> #include <utils/threads.h> +#include "ClientCache.h" #include "DisplayDevice.h" #include "DisplayHardware/HWC2.h" #include "DisplayHardware/PowerAdvisor.h" @@ -386,7 +387,7 @@ private: const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken, const InputWindowCommands& inputWindowCommands, - int64_t desiredPresentTime, const cached_buffer_t& uncacheBuffer, + int64_t desiredPresentTime, const client_cache_t& uncacheBuffer, const std::vector<ListenerCallbacks>& listenerCallbacks) override; void bootFinished() override; bool authenticateSurfaceTexture( @@ -545,7 +546,7 @@ private: const Vector<DisplayState>& displays, uint32_t flags, const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime, - const cached_buffer_t& uncacheBuffer, + const client_cache_t& uncacheBuffer, const std::vector<ListenerCallbacks>& listenerCallbacks, const int64_t postTime, bool privileged, bool isMainThread = false) REQUIRES(mStateLock); @@ -734,8 +735,8 @@ private: nsecs_t compositeToPresentLatency); void rebuildLayerStacks(); - ui::Dataspace getBestDataspace(const sp<const DisplayDevice>& display, - ui::Dataspace* outHdrDataSpace) const; + ui::Dataspace getBestDataspace(const sp<DisplayDevice>& display, ui::Dataspace* outHdrDataSpace, + bool* outIsHdrClientComposition) const; // Returns the appropriate ColorMode, Dataspace and RenderIntent for the // DisplayDevice. The function only returns the supported ColorMode, @@ -1031,7 +1032,7 @@ private: struct TransactionState { TransactionState(const Vector<ComposerState>& composerStates, const Vector<DisplayState>& displayStates, uint32_t transactionFlags, - int64_t desiredPresentTime, const cached_buffer_t& uncacheBuffer, + int64_t desiredPresentTime, const client_cache_t& uncacheBuffer, const std::vector<ListenerCallbacks>& listenerCallbacks, int64_t postTime, bool privileged) : states(composerStates), @@ -1047,7 +1048,7 @@ private: Vector<DisplayState> displays; uint32_t flags; const int64_t desiredPresentTime; - cached_buffer_t buffer; + client_cache_t buffer; std::vector<ListenerCallbacks> callback; const int64_t postTime; bool privileged; diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp index 78c6e74150..740099e350 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.cpp +++ b/services/surfaceflinger/TimeStats/TimeStats.cpp @@ -291,6 +291,9 @@ void TimeStats::setLatchTime(int32_t layerID, uint64_t frameNumber, nsecs_t latc std::lock_guard<std::mutex> lock(mMutex); if (!mTimeStatsTracker.count(layerID)) return; LayerRecord& layerRecord = mTimeStatsTracker[layerID]; + if (layerRecord.waitData < 0 || + layerRecord.waitData >= static_cast<int32_t>(layerRecord.timeRecords.size())) + return; TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData]; if (timeRecord.frameTime.frameNumber == frameNumber) { timeRecord.frameTime.latchTime = latchTime; @@ -306,6 +309,9 @@ void TimeStats::setDesiredTime(int32_t layerID, uint64_t frameNumber, nsecs_t de std::lock_guard<std::mutex> lock(mMutex); if (!mTimeStatsTracker.count(layerID)) return; LayerRecord& layerRecord = mTimeStatsTracker[layerID]; + if (layerRecord.waitData < 0 || + layerRecord.waitData >= static_cast<int32_t>(layerRecord.timeRecords.size())) + return; TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData]; if (timeRecord.frameTime.frameNumber == frameNumber) { timeRecord.frameTime.desiredTime = desiredTime; @@ -321,6 +327,9 @@ void TimeStats::setAcquireTime(int32_t layerID, uint64_t frameNumber, nsecs_t ac std::lock_guard<std::mutex> lock(mMutex); if (!mTimeStatsTracker.count(layerID)) return; LayerRecord& layerRecord = mTimeStatsTracker[layerID]; + if (layerRecord.waitData < 0 || + layerRecord.waitData >= static_cast<int32_t>(layerRecord.timeRecords.size())) + return; TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData]; if (timeRecord.frameTime.frameNumber == frameNumber) { timeRecord.frameTime.acquireTime = acquireTime; @@ -338,6 +347,9 @@ void TimeStats::setAcquireFence(int32_t layerID, uint64_t frameNumber, std::lock_guard<std::mutex> lock(mMutex); if (!mTimeStatsTracker.count(layerID)) return; LayerRecord& layerRecord = mTimeStatsTracker[layerID]; + if (layerRecord.waitData < 0 || + layerRecord.waitData >= static_cast<int32_t>(layerRecord.timeRecords.size())) + return; TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData]; if (timeRecord.frameTime.frameNumber == frameNumber) { timeRecord.acquireFence = acquireFence; @@ -353,6 +365,9 @@ void TimeStats::setPresentTime(int32_t layerID, uint64_t frameNumber, nsecs_t pr std::lock_guard<std::mutex> lock(mMutex); if (!mTimeStatsTracker.count(layerID)) return; LayerRecord& layerRecord = mTimeStatsTracker[layerID]; + if (layerRecord.waitData < 0 || + layerRecord.waitData >= static_cast<int32_t>(layerRecord.timeRecords.size())) + return; TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData]; if (timeRecord.frameTime.frameNumber == frameNumber) { timeRecord.frameTime.presentTime = presentTime; @@ -374,6 +389,9 @@ void TimeStats::setPresentFence(int32_t layerID, uint64_t frameNumber, std::lock_guard<std::mutex> lock(mMutex); if (!mTimeStatsTracker.count(layerID)) return; LayerRecord& layerRecord = mTimeStatsTracker[layerID]; + if (layerRecord.waitData < 0 || + layerRecord.waitData >= static_cast<int32_t>(layerRecord.timeRecords.size())) + return; TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData]; if (timeRecord.frameTime.frameNumber == frameNumber) { timeRecord.presentFence = presentFence; diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp index 34df6068ee..b1bf4e20d3 100644 --- a/services/surfaceflinger/TransactionCompletedThread.cpp +++ b/services/surfaceflinger/TransactionCompletedThread.cpp @@ -141,12 +141,12 @@ status_t TransactionCompletedThread::addPresentedCallbackHandles( } else { ALOGW("there are more latched callbacks than there were registered callbacks"); } + if (listener->second.size() == 0) { + mPendingTransactions.erase(listener); + } } else { ALOGW("cannot find listener in mPendingTransactions"); } - if (listener->second.size() == 0) { - mPendingTransactions.erase(listener); - } status_t err = addCallbackHandle(handle); if (err != NO_ERROR) { diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp index 7288232bf6..d3381e5757 100644 --- a/services/surfaceflinger/layerproto/LayerProtoParser.cpp +++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp @@ -299,6 +299,7 @@ std::string LayerProtoParser::Layer::to_string() const { StringAppendF(&result, "crop=%s, ", crop.to_string().c_str()); StringAppendF(&result, "cornerRadius=%f, ", cornerRadius); + StringAppendF(&result, "isProtected=%1d, ", isProtected); StringAppendF(&result, "isOpaque=%1d, invalidate=%1d, ", isOpaque, invalidate); StringAppendF(&result, "dataspace=%s, ", dataspace.c_str()); StringAppendF(&result, "defaultPixelFormat=%s, ", pixelFormat.c_str()); diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 85e9ce5f3f..f842d61c7f 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -35,7 +35,8 @@ cc_test { srcs: [ ":libsurfaceflinger_sources", "libsurfaceflinger_unittest_main.cpp", - "CompositionTest.cpp", + "CachingTest.cpp", + "CompositionTest.cpp", "DispSyncSourceTest.cpp", "DisplayIdentificationTest.cpp", "DisplayTransactionTest.cpp", diff --git a/services/surfaceflinger/tests/unittests/CachingTest.cpp b/services/surfaceflinger/tests/unittests/CachingTest.cpp new file mode 100644 index 0000000000..74ce540626 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/CachingTest.cpp @@ -0,0 +1,93 @@ +/* + * Copyright 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 "CachingTest" + +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <gui/BufferQueue.h> +#include "BufferStateLayer.h" + +namespace android { + +class SlotGenerationTest : public testing::Test { +protected: + BufferStateLayer::HwcSlotGenerator mHwcSlotGenerator; + sp<GraphicBuffer> mBuffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + sp<GraphicBuffer> mBuffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + sp<GraphicBuffer> mBuffer3{new GraphicBuffer(10, 10, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; +}; + +TEST_F(SlotGenerationTest, getHwcCacheSlot_Invalid) { + sp<IBinder> binder = new BBinder(); + // test getting invalid client_cache_id + client_cache_t id; + uint32_t slot = mHwcSlotGenerator.getHwcCacheSlot(id); + EXPECT_EQ(BufferQueue::INVALID_BUFFER_SLOT, slot); +} + +TEST_F(SlotGenerationTest, getHwcCacheSlot_Basic) { + sp<IBinder> binder = new BBinder(); + client_cache_t id; + id.token = binder; + id.id = 0; + uint32_t slot = mHwcSlotGenerator.getHwcCacheSlot(id); + EXPECT_EQ(BufferQueue::NUM_BUFFER_SLOTS - 1, slot); + + client_cache_t idB; + idB.token = binder; + idB.id = 1; + slot = mHwcSlotGenerator.getHwcCacheSlot(idB); + EXPECT_EQ(BufferQueue::NUM_BUFFER_SLOTS - 2, slot); + + slot = mHwcSlotGenerator.getHwcCacheSlot(idB); + EXPECT_EQ(BufferQueue::NUM_BUFFER_SLOTS - 2, slot); + + slot = mHwcSlotGenerator.getHwcCacheSlot(id); + EXPECT_EQ(BufferQueue::NUM_BUFFER_SLOTS - 1, slot); +} + +TEST_F(SlotGenerationTest, getHwcCacheSlot_Reuse) { + sp<IBinder> binder = new BBinder(); + std::vector<client_cache_t> ids; + uint32_t cacheId = 0; + // fill up cache + for (uint32_t i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { + client_cache_t id; + id.token = binder; + id.id = cacheId; + ids.push_back(id); + + uint32_t slot = mHwcSlotGenerator.getHwcCacheSlot(id); + EXPECT_EQ(BufferQueue::NUM_BUFFER_SLOTS - (i + 1), slot); + cacheId++; + } + for (uint32_t i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { + uint32_t slot = mHwcSlotGenerator.getHwcCacheSlot(ids[i]); + EXPECT_EQ(BufferQueue::NUM_BUFFER_SLOTS - (i + 1), slot); + } + + for (uint32_t i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { + client_cache_t id; + id.token = binder; + id.id = cacheId; + uint32_t slot = mHwcSlotGenerator.getHwcCacheSlot(id); + EXPECT_EQ(BufferQueue::NUM_BUFFER_SLOTS - (i + 1), slot); + cacheId++; + } +} +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h index bb9202054f..3c7e1da334 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h @@ -122,7 +122,6 @@ public: MOCK_METHOD3(setLayerPerFrameMetadataBlobs, Error(Display, Layer, const std::vector<IComposerClient::PerFrameMetadataBlob>&)); MOCK_METHOD2(setDisplayBrightness, Error(Display, float)); - MOCK_METHOD2(getDisplayBrightnessSupport, Error(Display, bool*)); }; } // namespace mock diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api index 7604c955c6..76503c8c17 100644 --- a/vulkan/api/vulkan.api +++ b/vulkan/api/vulkan.api @@ -96,7 +96,7 @@ define NULL_HANDLE 0 @extension("VK_KHR_win32_surface") define VK_KHR_WIN32_SURFACE_NAME "VK_KHR_win32_surface" // 11 -@extension("VK_ANDROID_native_buffer") define VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 7 +@extension("VK_ANDROID_native_buffer") define VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 8 @extension("VK_ANDROID_native_buffer") define VK_ANDROID_NATIVE_BUFFER_NAME "VK_ANDROID_native_buffer" // 12 diff --git a/vulkan/include/vulkan/vk_android_native_buffer.h b/vulkan/include/vulkan/vk_android_native_buffer.h index d3e5f0f6b1..23006fa6be 100644 --- a/vulkan/include/vulkan/vk_android_native_buffer.h +++ b/vulkan/include/vulkan/vk_android_native_buffer.h @@ -37,7 +37,17 @@ extern "C" { * backwards-compatibility support is temporary, and will likely be removed in * (along with all gralloc0 support) in a future release. */ -#define VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 7 +/* NOTE ON VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 8 + * + * This version of the extension doesn't introduce new types or structs, but is + * to accommodate the new struct VkBindImageMemorySwapchainInfoKHR added in + * VK_KHR_swapchain spec version 69. When VkBindImageMemorySwapchainInfoKHR is + * chained in the pNext chain of VkBindImageMemoryInfo, a VkNativeBufferANDROID + * that holds the correct gralloc handle according to the imageIndex specified + * in VkBindImageMemorySwapchainInfoKHR will be additionally chained to the + * pNext chain of VkBindImageMemoryInfo and passed down to the driver. + */ +#define VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 8 #define VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME "VK_ANDROID_native_buffer" #define VK_ANDROID_NATIVE_BUFFER_ENUM(type,id) ((type)(1000000000 + (1000 * (VK_ANDROID_NATIVE_BUFFER_EXTENSION_NUMBER - 1)) + (id))) diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp index 491d4d1343..613fa1352a 100644 --- a/vulkan/libvulkan/driver.cpp +++ b/vulkan/libvulkan/driver.cpp @@ -983,7 +983,12 @@ VkResult EnumerateDeviceExtensionProperties( memcpy(prop.extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME, sizeof(VK_KHR_SWAPCHAIN_EXTENSION_NAME)); - prop.specVersion = VK_KHR_SWAPCHAIN_SPEC_VERSION; + + if (prop.specVersion >= 8) { + prop.specVersion = VK_KHR_SWAPCHAIN_SPEC_VERSION; + } else { + prop.specVersion = 68; + } } } |