diff options
Diffstat (limited to 'libs')
| -rw-r--r-- | libs/gui/ISurfaceComposer.cpp | 12 | ||||
| -rw-r--r-- | libs/gui/LayerState.cpp | 4 | ||||
| -rw-r--r-- | libs/gui/SurfaceComposerClient.cpp | 162 | ||||
| -rw-r--r-- | libs/gui/include/gui/ISurfaceComposer.h | 4 | ||||
| -rw-r--r-- | libs/gui/include/gui/LayerState.h | 9 | ||||
| -rw-r--r-- | libs/gui/include/gui/SurfaceComposerClient.h | 10 | ||||
| -rw-r--r-- | libs/gui/tests/Surface_test.cpp | 3 | ||||
| -rw-r--r-- | libs/ui/GraphicBuffer.cpp | 7 | ||||
| -rw-r--r-- | libs/ui/include/ui/GraphicBuffer.h | 20 |
9 files changed, 149 insertions, 82 deletions
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 247dc8d9d2..bc63d315e0 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -68,7 +68,8 @@ public: const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken, const InputWindowCommands& commands, - int64_t desiredPresentTime) { + int64_t desiredPresentTime, + const cached_buffer_t& uncacheBuffer) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); @@ -86,6 +87,8 @@ public: data.writeStrongBinder(applyToken); commands.write(data); data.writeInt64(desiredPresentTime); + data.writeStrongBinder(uncacheBuffer.token); + data.writeUint64(uncacheBuffer.cacheId); remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply); } @@ -970,8 +973,13 @@ status_t BnSurfaceComposer::onTransact( inputWindowCommands.read(data); int64_t desiredPresentTime = data.readInt64(); + + cached_buffer_t uncachedBuffer; + uncachedBuffer.token = data.readStrongBinder(); + uncachedBuffer.cacheId = data.readUint64(); + setTransactionState(state, displays, stateFlags, applyToken, inputWindowCommands, - desiredPresentTime); + desiredPresentTime, uncachedBuffer); return NO_ERROR; } case BOOT_FINISHED: { diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 84ba64494f..f6ca9e8f0b 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -95,7 +95,7 @@ status_t layer_state_t::write(Parcel& output) const } output.writeStrongBinder(cachedBuffer.token); - output.writeInt32(cachedBuffer.bufferId); + output.writeUint64(cachedBuffer.cacheId); output.writeParcelable(metadata); output.writeFloat(bgColorAlpha); @@ -173,7 +173,7 @@ status_t layer_state_t::read(const Parcel& input) } cachedBuffer.token = input.readStrongBinder(); - cachedBuffer.bufferId = input.readInt32(); + cachedBuffer.cacheId = input.readUint64(); input.readParcelable(&metadata); bgColorAlpha = input.readFloat(); diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index b0e827536d..39cd62fa10 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -233,6 +233,8 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener // --------------------------------------------------------------------------- +void bufferCacheCallback(void* /*context*/, uint64_t graphicBufferId); + class BufferCache : public Singleton<BufferCache> { public: BufferCache() : token(new BBinder()) {} @@ -241,77 +243,57 @@ public: return IInterface::asBinder(TransactionCompletedListener::getIInstance()); } - int32_t getId(const sp<GraphicBuffer>& buffer) { + status_t getCacheId(const sp<GraphicBuffer>& buffer, uint64_t* cacheId) { std::lock_guard<std::mutex> lock(mMutex); - auto itr = mBuffers.find(buffer); + auto itr = mBuffers.find(buffer->getId()); if (itr == mBuffers.end()) { - return -1; + return BAD_VALUE; } - itr->second.counter = getCounter(); - return itr->second.id; + itr->second = getCounter(); + *cacheId = buffer->getId(); + return NO_ERROR; } - int32_t cache(const sp<GraphicBuffer>& buffer) { + uint64_t cache(const sp<GraphicBuffer>& buffer) { std::lock_guard<std::mutex> lock(mMutex); - int32_t bufferId = getNextAvailableId(); + if (mBuffers.size() >= BUFFER_CACHE_MAX_SIZE) { + evictLeastRecentlyUsedBuffer(); + } + + buffer->addDeathCallback(bufferCacheCallback, nullptr); - mBuffers[buffer].id = bufferId; - mBuffers[buffer].counter = getCounter(); - return bufferId; + mBuffers[buffer->getId()] = getCounter(); + return buffer->getId(); } -private: - int32_t evictDestroyedBuffer() REQUIRES(mMutex) { - auto itr = mBuffers.begin(); - while (itr != mBuffers.end()) { - auto& buffer = itr->first; - if (buffer == nullptr || buffer.promote() == nullptr) { - int32_t bufferId = itr->second.id; - mBuffers.erase(itr); - return bufferId; - } - itr++; - } - return -1; + void uncache(uint64_t cacheId) { + std::lock_guard<std::mutex> lock(mMutex); + uncacheLocked(cacheId); } - int32_t evictLeastRecentlyUsedBuffer() REQUIRES(mMutex) { - if (mBuffers.size() < 0) { - return -1; - } + void uncacheLocked(uint64_t cacheId) REQUIRES(mMutex) { + mBuffers.erase(cacheId); + SurfaceComposerClient::doUncacheBufferTransaction(cacheId); + } + +private: + void evictLeastRecentlyUsedBuffer() REQUIRES(mMutex) { auto itr = mBuffers.begin(); - uint64_t minCounter = itr->second.counter; + uint64_t minCounter = itr->second; auto minBuffer = itr; itr++; while (itr != mBuffers.end()) { - uint64_t counter = itr->second.counter; + uint64_t counter = itr->second; if (counter < minCounter) { minCounter = counter; minBuffer = itr; } itr++; } - int32_t minBufferId = minBuffer->second.id; - mBuffers.erase(minBuffer); - return minBufferId; - } - - int32_t getNextAvailableId() REQUIRES(mMutex) { - static int32_t id = 0; - if (id + 1 < BUFFER_CACHE_MAX_SIZE) { - return id++; - } - - // There are no more valid cache ids. To set additional buffers, evict existing buffers - // and reuse their cache ids. - int32_t bufferId = evictDestroyedBuffer(); - if (bufferId > 0) { - return bufferId; - } - return evictLeastRecentlyUsedBuffer(); + uncacheLocked(minBuffer->first); } uint64_t getCounter() REQUIRES(mMutex) { @@ -319,18 +301,8 @@ private: return counter++; } - struct Metadata { - // The cache id of a buffer that can be set to ISurfaceComposer. When ISurfaceComposer - // recieves this id, it can retrieve the buffer from its cache. Caching GraphicBuffers - // is important because sending them across processes is expensive. - int32_t id = 0; - // When a buffer is set, a counter is incremented and stored in the cache's metadata. - // When an buffer must be evicted, the entry with the lowest counter value is chosen. - uint64_t counter = 0; - }; - std::mutex mMutex; - std::map<wp<GraphicBuffer>, Metadata> mBuffers GUARDED_BY(mMutex); + std::map<uint64_t /*Cache id*/, uint64_t /*counter*/> mBuffers GUARDED_BY(mMutex); // Used by ISurfaceComposer to identify which process is sending the cached buffer. sp<IBinder> token; @@ -338,6 +310,11 @@ private: ANDROID_SINGLETON_STATIC_INSTANCE(BufferCache); +void bufferCacheCallback(void* /*context*/, uint64_t graphicBufferId) { + // GraphicBuffer id's are used as the cache ids. + BufferCache::getInstance().uncache(graphicBufferId); +} + // --------------------------------------------------------------------------- SurfaceComposerClient::Transaction::Transaction(const Transaction& other) @@ -385,6 +362,9 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr mInputWindowCommands.merge(other.mInputWindowCommands); other.mInputWindowCommands.clear(); + mContainsBuffer = other.mContainsBuffer; + other.mContainsBuffer = false; + return *this; } @@ -401,7 +381,50 @@ void SurfaceComposerClient::doDropReferenceTransaction(const sp<IBinder>& handle s.state.parentHandleForChild = nullptr; composerStates.add(s); - sf->setTransactionState(composerStates, displayStates, 0, nullptr, {}, -1); + sf->setTransactionState(composerStates, displayStates, 0, nullptr, {}, -1, {}); +} + +void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) { + sp<ISurfaceComposer> sf(ComposerService::getComposerService()); + + cached_buffer_t uncacheBuffer; + uncacheBuffer.token = BufferCache::getInstance().getToken(); + uncacheBuffer.cacheId = cacheId; + + sf->setTransactionState({}, {}, 0, nullptr, {}, -1, uncacheBuffer); +} + +void SurfaceComposerClient::Transaction::cacheBuffers() { + if (!mContainsBuffer) { + return; + } + + size_t count = 0; + for (auto& [sc, cs] : mComposerStates) { + layer_state_t* s = getLayerState(sc); + if (!(s->what & layer_state_t::eBufferChanged)) { + continue; + } + + uint64_t cacheId = 0; + status_t ret = BufferCache::getInstance().getCacheId(s->buffer, &cacheId); + if (ret == NO_ERROR) { + s->what &= ~static_cast<uint32_t>(layer_state_t::eBufferChanged); + s->buffer = nullptr; + } else { + cacheId = BufferCache::getInstance().cache(s->buffer); + } + s->what |= layer_state_t::eCachedBufferChanged; + s->cachedBuffer.token = BufferCache::getInstance().getToken(); + s->cachedBuffer.cacheId = 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 + count++; + if (count >= BUFFER_CACHE_MAX_SIZE) { + break; + } + } } status_t SurfaceComposerClient::Transaction::apply(bool synchronous) { @@ -437,6 +460,8 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous) { } mListenerCallbacks.clear(); + cacheBuffers(); + Vector<ComposerState> composerStates; Vector<DisplayState> displayStates; uint32_t flags = 0; @@ -468,7 +493,8 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous) { sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); sf->setTransactionState(composerStates, displayStates, flags, applyToken, mInputWindowCommands, - mDesiredPresentTime); + mDesiredPresentTime, + {} /*uncacheBuffer - only set in doUncacheBufferTransaction*/); mInputWindowCommands.clear(); mStatus = NO_ERROR; return NO_ERROR; @@ -882,20 +908,12 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffe mStatus = BAD_INDEX; return *this; } - - int32_t bufferId = BufferCache::getInstance().getId(buffer); - if (bufferId < 0) { - bufferId = BufferCache::getInstance().cache(buffer); - - s->what |= layer_state_t::eBufferChanged; - s->buffer = buffer; - } - - s->what |= layer_state_t::eCachedBufferChanged; - s->cachedBuffer.token = BufferCache::getInstance().getToken(); - s->cachedBuffer.bufferId = bufferId; + s->what |= layer_state_t::eBufferChanged; + s->buffer = buffer; registerSurfaceControlForCallback(sc); + + mContainsBuffer = true; return *this; } diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 8f54fee22f..0ef5b39641 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -40,6 +40,7 @@ namespace android { // ---------------------------------------------------------------------------- +struct cached_buffer_t; struct ComposerState; struct DisplayState; struct DisplayInfo; @@ -131,7 +132,8 @@ public: const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken, const InputWindowCommands& inputWindowCommands, - int64_t desiredPresentTime) = 0; + int64_t desiredPresentTime, + const cached_buffer_t& uncacheBuffer) = 0; /* signal that we're done booting. * Requires ACCESS_SURFACE_FLINGER permission diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 35e795c30b..77bf8f1dc5 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -41,6 +41,11 @@ namespace android { class Parcel; class ISurfaceComposerClient; +struct cached_buffer_t { + sp<IBinder> token = nullptr; + uint64_t cacheId; +}; + /* * Used to communicate layer information between SurfaceFlinger and its clients. */ @@ -133,10 +138,6 @@ struct layer_state_t { float dtdy{0}; float dsdy{0}; }; - struct cached_buffer_t { - sp<IBinder> token = nullptr; - int32_t bufferId = -1; - }; sp<IBinder> surface; uint64_t what; float x; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 39d6d13682..593a5e7d81 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -165,6 +165,12 @@ public: 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. + */ + static void doUncacheBufferTransaction(uint64_t cacheId); + // Queries whether a given display is wide color display. static status_t isWideColorDisplay(const sp<IBinder>& display, bool* outIsWideColorDisplay); @@ -279,6 +285,9 @@ public: bool mAnimation = false; bool mEarlyWakeup = false; + // Indicates that the Transaction contains a buffer that should be cached + bool mContainsBuffer = false; + // mDesiredPresentTime is the time in nanoseconds that the client would like the transaction // to be presented. When it is not possible to present at exactly that time, it will be // presented after the time has passed. @@ -297,6 +306,7 @@ public: layer_state_t* getLayerState(const sp<SurfaceControl>& sc); DisplayState& getDisplayState(const sp<IBinder>& token); + void cacheBuffers(); void registerSurfaceControlForCallback(const sp<SurfaceControl>& sc); public: diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 06fe86c0cf..94b669dde4 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -560,7 +560,8 @@ public: const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/, const sp<IBinder>& /*applyToken*/, const InputWindowCommands& /*inputWindowCommands*/, - int64_t /*desiredPresentTime*/) override {} + int64_t /*desiredPresentTime*/, + const cached_buffer_t& /*cachedBuffer*/) override {} void bootFinished() override {} bool authenticateSurfaceTexture( diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp index f800627ef7..637a9cf725 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -133,6 +133,9 @@ GraphicBuffer::~GraphicBuffer() if (handle) { free_handle(); } + for (auto& [callback, context] : mDeathCallbacks) { + callback(context, mId); + } } void GraphicBuffer::free_handle() @@ -534,6 +537,10 @@ status_t GraphicBuffer::unflatten( return NO_ERROR; } +void GraphicBuffer::addDeathCallback(GraphicBufferDeathCallback deathCallback, void* context) { + mDeathCallbacks.emplace_back(deathCallback, context); +} + #ifndef LIBUI_IN_VNDK bool GraphicBuffer::isBufferHubBuffer() const { return mBufferHubBuffer != nullptr; diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h index 1c88777961..f86ca59b52 100644 --- a/libs/ui/include/ui/GraphicBuffer.h +++ b/libs/ui/include/ui/GraphicBuffer.h @@ -21,6 +21,8 @@ #include <sys/types.h> #include <string> +#include <utility> +#include <vector> #include <android/hardware_buffer.h> #include <ui/ANativeObjectBase.h> @@ -42,6 +44,8 @@ class BufferHubBuffer; class GraphicBufferMapper; +using GraphicBufferDeathCallback = std::function<void(void* /*context*/, uint64_t bufferId)>; + // =========================================================================== // GraphicBuffer // =========================================================================== @@ -219,6 +223,8 @@ public: return mBufferMapper.getMapperVersion(); } + void addDeathCallback(GraphicBufferDeathCallback deathCallback, void* context); + #ifndef LIBUI_IN_VNDK // Returns whether this GraphicBuffer is backed by BufferHubBuffer. bool isBufferHubBuffer() const; @@ -280,6 +286,20 @@ private: // IGBP::setGenerationNumber), attempts to attach the buffer will fail. uint32_t mGenerationNumber; + // Send a callback when a GraphicBuffer dies. + // + // This is used for BufferStateLayer caching. GraphicBuffers are refcounted per process. When + // A GraphicBuffer doesn't have any more sp<> in a process, it is destroyed. This causes + // problems when trying to implicitcly cache across process boundaries. Ideally, both sides + // of the cache would hold onto wp<> references. When an app dropped its sp<>, the GraphicBuffer + // would be destroyed. Unfortunately, when SurfaceFlinger has only a wp<> reference to the + // GraphicBuffer, it immediately goes out of scope in the SurfaceFlinger process. SurfaceFlinger + // must hold onto a sp<> to the buffer. When the GraphicBuffer goes out of scope in the app's + // process, the client side cache will get this callback. It erases the buffer from its cache + // and informs SurfaceFlinger that it should drop its strong pointer reference to the buffer. + std::vector<std::pair<GraphicBufferDeathCallback, void* /*mDeathCallbackContext*/>> + mDeathCallbacks; + #ifndef LIBUI_IN_VNDK // Stores a BufferHubBuffer that handles buffer signaling, identification. std::unique_ptr<BufferHubBuffer> mBufferHubBuffer; |