Merge "blast: implicitly cache buffers"
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index bef68ef..fd30e3b 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -722,42 +722,6 @@
return error;
}
- virtual status_t cacheBuffer(const sp<IBinder>& token, const sp<GraphicBuffer>& buffer,
- int32_t* outBufferId) {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-
- data.writeStrongBinder(token);
- if (buffer) {
- data.writeBool(true);
- data.write(*buffer);
- } else {
- data.writeBool(false);
- }
-
- status_t result = remote()->transact(BnSurfaceComposer::CACHE_BUFFER, data, &reply);
- if (result != NO_ERROR) {
- return result;
- }
-
- int32_t id = -1;
- result = reply.readInt32(&id);
- if (result == NO_ERROR) {
- *outBufferId = id;
- }
- return result;
- }
-
- virtual status_t uncacheBuffer(const sp<IBinder>& token, int32_t bufferId) {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-
- data.writeStrongBinder(token);
- data.writeInt32(bufferId);
-
- return remote()->transact(BnSurfaceComposer::UNCACHE_BUFFER, data, &reply);
- }
-
virtual status_t isWideColorDisplay(const sp<IBinder>& token,
bool* outIsWideColorDisplay) const {
Parcel data, reply;
@@ -1238,48 +1202,6 @@
}
return error;
}
- case CACHE_BUFFER: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> token;
- status_t result = data.readStrongBinder(&token);
- if (result != NO_ERROR) {
- ALOGE("cache buffer failure in reading token: %d", result);
- return result;
- }
-
- sp<GraphicBuffer> buffer = new GraphicBuffer();
- if (data.readBool()) {
- result = data.read(*buffer);
- if (result != NO_ERROR) {
- ALOGE("cache buffer failure in reading buffer: %d", result);
- return result;
- }
- }
- int32_t bufferId = -1;
- status_t error = cacheBuffer(token, buffer, &bufferId);
- if (error == NO_ERROR) {
- reply->writeInt32(bufferId);
- }
- return error;
- }
- case UNCACHE_BUFFER: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> token;
- status_t result = data.readStrongBinder(&token);
- if (result != NO_ERROR) {
- ALOGE("uncache buffer failure in reading token: %d", result);
- return result;
- }
-
- int32_t bufferId = -1;
- result = data.readInt32(&bufferId);
- if (result != NO_ERROR) {
- ALOGE("uncache buffer failure in reading buffer id: %d", result);
- return result;
- }
-
- return uncacheBuffer(token, bufferId);
- }
case IS_WIDE_COLOR_DISPLAY: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> display = nullptr;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 51385b8..92b5588 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -48,6 +48,9 @@
#include <private/gui/ComposerService.h>
+// This server size should always be smaller than the server cache size
+#define BUFFER_CACHE_MAX_SIZE 64
+
namespace android {
using ui::ColorMode;
@@ -230,6 +233,113 @@
// ---------------------------------------------------------------------------
+class BufferCache : public Singleton<BufferCache> {
+public:
+ BufferCache() : token(new BBinder()) {}
+
+ sp<IBinder> getToken() {
+ return IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ }
+
+ int32_t getId(const sp<GraphicBuffer>& buffer) {
+ std::lock_guard lock(mMutex);
+
+ auto itr = mBuffers.find(buffer);
+ if (itr == mBuffers.end()) {
+ return -1;
+ }
+ itr->second.counter = getCounter();
+ return itr->second.id;
+ }
+
+ int32_t cache(const sp<GraphicBuffer>& buffer) {
+ std::lock_guard lock(mMutex);
+
+ int32_t bufferId = getNextAvailableId();
+
+ mBuffers[buffer].id = bufferId;
+ mBuffers[buffer].counter = getCounter();
+ return bufferId;
+ }
+
+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;
+ }
+
+ int32_t evictLeastRecentlyUsedBuffer() REQUIRES(mMutex) {
+ if (mBuffers.size() < 0) {
+ return -1;
+ }
+ auto itr = mBuffers.begin();
+ uint64_t minCounter = itr->second.counter;
+ auto minBuffer = itr;
+ itr++;
+
+ while (itr != mBuffers.end()) {
+ uint64_t counter = itr->second.counter;
+ 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();
+ }
+
+ uint64_t getCounter() REQUIRES(mMutex) {
+ static uint64_t counter = 0;
+ 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);
+
+ // Used by ISurfaceComposer to identify which process is sending the cached buffer.
+ sp<IBinder> token;
+};
+
+ANDROID_SINGLETON_STATIC_INSTANCE(BufferCache);
+
+// ---------------------------------------------------------------------------
+
SurfaceComposerClient::Transaction::Transaction(const Transaction& other)
: mForceSynchronous(other.mForceSynchronous),
mTransactionNestCount(other.mTransactionNestCount),
@@ -759,22 +869,17 @@
mStatus = BAD_INDEX;
return *this;
}
- s->what |= layer_state_t::eBufferChanged;
- s->buffer = buffer;
- registerSurfaceControlForCallback(sc);
- return *this;
-}
+ int32_t bufferId = BufferCache::getInstance().getId(buffer);
+ if (bufferId < 0) {
+ bufferId = BufferCache::getInstance().cache(buffer);
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCachedBuffer(
- const sp<SurfaceControl>& sc, int32_t bufferId) {
- layer_state_t* s = getLayerState(sc);
- if (!s) {
- mStatus = BAD_INDEX;
- return *this;
+ s->what |= layer_state_t::eBufferChanged;
+ s->buffer = buffer;
}
+
s->what |= layer_state_t::eCachedBufferChanged;
- s->cachedBuffer.token = IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ s->cachedBuffer.token = BufferCache::getInstance().getToken();
s->cachedBuffer.bufferId = bufferId;
registerSurfaceControlForCallback(sc);
@@ -1217,26 +1322,6 @@
// ----------------------------------------------------------------------------
-status_t SurfaceComposerClient::cacheBuffer(const sp<GraphicBuffer>& buffer, int32_t* outBufferId) {
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- if (buffer == nullptr || outBufferId == nullptr) {
- return BAD_VALUE;
- }
- return sf->cacheBuffer(IInterface::asBinder(TransactionCompletedListener::getIInstance()),
- buffer, outBufferId);
-}
-
-status_t SurfaceComposerClient::uncacheBuffer(int32_t bufferId) {
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- if (bufferId < 0) {
- return BAD_VALUE;
- }
- return sf->uncacheBuffer(IInterface::asBinder(TransactionCompletedListener::getIInstance()),
- bufferId);
-}
-
-// ----------------------------------------------------------------------------
-
status_t SurfaceComposerClient::enableVSyncInjections(bool enable) {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
return sf->enableVSyncInjections(enable);
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 3899f6a..7146b7d 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -320,11 +320,6 @@
*/
virtual status_t getProtectedContentSupport(bool* outSupported) const = 0;
- virtual status_t cacheBuffer(const sp<IBinder>& token, const sp<GraphicBuffer>& buffer,
- int32_t* outBufferId) = 0;
-
- virtual status_t uncacheBuffer(const sp<IBinder>& token, int32_t bufferId) = 0;
-
/*
* Queries whether the given display is a wide color display.
* Requires the ACCESS_SURFACE_FLINGER permission.
@@ -373,8 +368,6 @@
SET_DISPLAY_CONTENT_SAMPLING_ENABLED,
GET_DISPLAYED_CONTENT_SAMPLE,
GET_PROTECTED_CONTENT_SUPPORT,
- CACHE_BUFFER,
- UNCACHE_BUFFER,
IS_WIDE_COLOR_DISPLAY,
GET_DISPLAY_NATIVE_PRIMARIES,
// Always append new enum to the end.
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index a95664b..044106d 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -152,12 +152,6 @@
static void doDropReferenceTransaction(const sp<IBinder>& handle,
const sp<ISurfaceComposerClient>& client);
- // Caches a buffer with the ISurfaceComposer so the buffer does not need to be resent across
- // processes
- static status_t cacheBuffer(const sp<GraphicBuffer>& buffer, int32_t* outBufferId);
- // Uncaches a buffer set by cacheBuffer
- static status_t uncacheBuffer(int32_t bufferId);
-
// Queries whether a given display is wide color display.
static status_t isWideColorDisplay(const sp<IBinder>& display, bool* outIsWideColorDisplay);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 1705fd7..8bd589d 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -664,11 +664,6 @@
status_t getColorManagement(bool* /*outGetColorManagement*/) const override { return NO_ERROR; }
status_t getProtectedContentSupport(bool* /*outSupported*/) const override { return NO_ERROR; }
- status_t cacheBuffer(const sp<IBinder>& /*token*/, const sp<GraphicBuffer>& /*buffer*/,
- int32_t* /*outBufferId*/) {
- return NO_ERROR;
- }
- status_t uncacheBuffer(const sp<IBinder>& /*token*/, int32_t /*bufferId*/) { return NO_ERROR; }
status_t isWideColorDisplay(const sp<IBinder>&, bool*) const override { return NO_ERROR; }
protected:
diff --git a/services/surfaceflinger/BufferStateLayerCache.cpp b/services/surfaceflinger/BufferStateLayerCache.cpp
index c82ad7b..cb02d16 100644
--- a/services/surfaceflinger/BufferStateLayerCache.cpp
+++ b/services/surfaceflinger/BufferStateLayerCache.cpp
@@ -19,81 +19,84 @@
#define LOG_TAG "BufferStateLayerCache"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <cinttypes>
+
#include "BufferStateLayerCache.h"
-#define MAX_CACHE_SIZE 64
+#define VALID_CACHE_ID(id) ((id) >= 0 || (id) < (BUFFER_CACHE_MAX_SIZE))
namespace android {
-int32_t BufferStateLayerCache::add(const sp<IBinder>& processToken,
- const sp<GraphicBuffer>& buffer) {
- std::lock_guard lock(mMutex);
+ANDROID_SINGLETON_STATIC_INSTANCE(BufferStateLayerCache);
- auto& processCache = getProccessCache(processToken);
+BufferStateLayerCache::BufferStateLayerCache() : mDeathRecipient(new CacheDeathRecipient) {}
- int32_t slot = findSlot(processCache);
- if (slot < 0) {
- return slot;
+void BufferStateLayerCache::add(sp<IBinder> processToken, int32_t id,
+ const sp<GraphicBuffer>& buffer) {
+ if (!VALID_CACHE_ID(id)) {
+ ALOGE("failed to cache buffer: invalid buffer id");
+ return;
}
- processCache[slot] = buffer;
+ if (!processToken) {
+ ALOGE("failed to cache buffer: invalid process token");
+ return;
+ }
- return slot;
-}
-
-void BufferStateLayerCache::release(const sp<IBinder>& processToken, int32_t id) {
- if (id < 0) {
- ALOGE("invalid buffer id");
+ if (!buffer) {
+ ALOGE("failed to cache buffer: invalid buffer");
return;
}
std::lock_guard lock(mMutex);
- auto& processCache = getProccessCache(processToken);
- if (id >= processCache.size()) {
- ALOGE("invalid buffer id");
- return;
- }
- processCache[id] = nullptr;
-}
-
-sp<GraphicBuffer> BufferStateLayerCache::get(const sp<IBinder>& processToken, int32_t id) {
- if (id < 0) {
- ALOGE("invalid buffer id");
- return nullptr;
- }
-
- std::lock_guard lock(mMutex);
- auto& processCache = getProccessCache(processToken);
-
- if (id >= processCache.size()) {
- ALOGE("invalid buffer id");
- return nullptr;
- }
- return processCache[id];
-}
-
-std::vector<sp<GraphicBuffer>>& BufferStateLayerCache::getProccessCache(
- const sp<IBinder>& processToken) {
- return mBuffers[processToken];
-}
-
-int32_t BufferStateLayerCache::findSlot(std::vector<sp<GraphicBuffer>>& processCache) {
- int32_t slot = 0;
-
- for (const sp<GraphicBuffer> buffer : processCache) {
- if (!buffer) {
- return slot;
+ // 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;
}
- slot++;
}
- if (processCache.size() < MAX_CACHE_SIZE) {
- processCache.push_back(nullptr);
- return slot;
+ auto& processBuffers = mBuffers[processToken];
+ processBuffers[id] = buffer;
+}
+
+sp<GraphicBuffer> BufferStateLayerCache::get(sp<IBinder> processToken, int32_t id) {
+ if (!VALID_CACHE_ID(id)) {
+ ALOGE("failed to get buffer: invalid buffer id");
+ return nullptr;
}
- return -1;
+ 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 (id >= itr->second.size()) {
+ ALOGE("failed to get buffer: id outside the bounds of the cache");
+ 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/BufferStateLayerCache.h b/services/surfaceflinger/BufferStateLayerCache.h
index 623f0c6..ede3feb 100644
--- a/services/surfaceflinger/BufferStateLayerCache.h
+++ b/services/surfaceflinger/BufferStateLayerCache.h
@@ -20,36 +20,36 @@
#include <binder/IBinder.h>
#include <ui/GraphicBuffer.h>
#include <utils/RefBase.h>
+#include <utils/Singleton.h>
+#include <array>
+#include <map>
#include <mutex>
-#include <unordered_map>
-#include <vector>
+
+#define BUFFER_CACHE_MAX_SIZE 64
namespace android {
-class BufferStateLayerCache {
+class BufferStateLayerCache : public Singleton<BufferStateLayerCache> {
public:
- int32_t add(const sp<IBinder>& processToken, const sp<GraphicBuffer>& buffer);
- void release(const sp<IBinder>& processToken, int32_t id);
+ BufferStateLayerCache();
- sp<GraphicBuffer> get(const sp<IBinder>& processToken, int32_t id);
+ void add(sp<IBinder> processToken, int32_t id, const sp<GraphicBuffer>& buffer);
+ sp<GraphicBuffer> get(sp<IBinder> processToken, int32_t id);
+
+ void removeProcess(const wp<IBinder>& processToken);
private:
std::mutex mMutex;
+ std::map<wp<IBinder> /*caching process*/, std::array<sp<GraphicBuffer>, BUFFER_CACHE_MAX_SIZE>>
+ mBuffers GUARDED_BY(mMutex);
- std::vector<sp<GraphicBuffer>>& getProccessCache(const sp<IBinder>& processToken)
- REQUIRES(mMutex);
-
- int32_t findSlot(std::vector<sp<GraphicBuffer>>& proccessCache) REQUIRES(mMutex);
-
- struct IBinderHash {
- std::size_t operator()(const sp<IBinder>& strongPointer) const {
- return std::hash<IBinder*>{}(strongPointer.get());
- }
+ class CacheDeathRecipient : public IBinder::DeathRecipient {
+ public:
+ void binderDied(const wp<IBinder>& who) override;
};
- std::unordered_map<sp<IBinder> /*caching process*/, std::vector<sp<GraphicBuffer>>, IBinderHash>
- mBuffers GUARDED_BY(mMutex);
+ sp<CacheDeathRecipient> mDeathRecipient;
};
}; // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index baefb15..9d03ae7 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1159,20 +1159,6 @@
return NO_ERROR;
}
-status_t SurfaceFlinger::cacheBuffer(const sp<IBinder>& token, const sp<GraphicBuffer>& buffer,
- int32_t* outBufferId) {
- if (!outBufferId) {
- return BAD_VALUE;
- }
- *outBufferId = mBufferStateLayerCache.add(token, buffer);
- return NO_ERROR;
-}
-
-status_t SurfaceFlinger::uncacheBuffer(const sp<IBinder>& token, int32_t bufferId) {
- mBufferStateLayerCache.release(token, bufferId);
- return NO_ERROR;
-}
-
status_t SurfaceFlinger::isWideColorDisplay(const sp<IBinder>& displayToken,
bool* outIsWideColorDisplay) const {
if (!displayToken || !outIsWideColorDisplay) {
@@ -3999,9 +3985,6 @@
if (what & layer_state_t::eFrameChanged) {
if (layer->setFrame(s.frame)) flags |= eTraversalNeeded;
}
- if (what & layer_state_t::eBufferChanged) {
- if (layer->setBuffer(s.buffer)) flags |= eTraversalNeeded;
- }
if (what & layer_state_t::eAcquireFenceChanged) {
if (layer->setAcquireFence(s.acquireFence)) flags |= eTraversalNeeded;
}
@@ -4038,9 +4021,16 @@
callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface));
}
}
+
+ if (what & layer_state_t::eBufferChanged) {
+ // Add the new buffer to the cache. This should always come before eCachedBufferChanged.
+ BufferStateLayerCache::getInstance().add(s.cachedBuffer.token, s.cachedBuffer.bufferId,
+ s.buffer);
+ }
if (what & layer_state_t::eCachedBufferChanged) {
sp<GraphicBuffer> buffer =
- mBufferStateLayerCache.get(s.cachedBuffer.token, s.cachedBuffer.bufferId);
+ BufferStateLayerCache::getInstance().get(s.cachedBuffer.token,
+ s.cachedBuffer.bufferId);
if (layer->setBuffer(buffer)) flags |= eTraversalNeeded;
}
if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded;
@@ -5022,8 +5012,6 @@
case GET_COLOR_MANAGEMENT:
case GET_COMPOSITION_PREFERENCE:
case GET_PROTECTED_CONTENT_SUPPORT:
- case CACHE_BUFFER:
- case UNCACHE_BUFFER:
case IS_WIDE_COLOR_DISPLAY: {
return OK;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 689ec1c..a127550 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -467,9 +467,6 @@
uint64_t timestamp,
DisplayedFrameStats* outStats) const override;
status_t getProtectedContentSupport(bool* outSupported) const override;
- status_t cacheBuffer(const sp<IBinder>& token, const sp<GraphicBuffer>& buffer,
- int32_t* outBufferId) override;
- status_t uncacheBuffer(const sp<IBinder>& token, int32_t bufferId) override;
status_t isWideColorDisplay(const sp<IBinder>& displayToken,
bool* outIsWideColorDisplay) const override;
@@ -1089,8 +1086,6 @@
InputWindowCommands mInputWindowCommands;
- BufferStateLayerCache mBufferStateLayerCache;
-
ui::DisplayPrimaries mInternalDisplayPrimaries;
};
}; // namespace android
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 4f0ded3..e631295 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -2405,6 +2405,117 @@
}
}
+TEST_F(LayerRenderTypeTransactionTest, SetBufferCaching_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ std::array<Color, 4> colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN};
+
+ std::array<sp<GraphicBuffer>, 10> buffers;
+
+ size_t idx = 0;
+ for (auto& buffer : buffers) {
+ buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ Color color = colors[idx % colors.size()];
+ fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
+ idx++;
+ }
+
+ // Set each buffer twice. The first time adds it to the cache, the second time tests that the
+ // cache is working.
+ idx = 0;
+ for (auto& buffer : buffers) {
+ for (int i = 0; i < 2; i++) {
+ Transaction().setBuffer(layer, buffer).apply();
+
+ Color color = colors[idx % colors.size()];
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), color);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+ idx++;
+ }
+}
+
+TEST_F(LayerRenderTypeTransactionTest, SetBufferCaching_LeastRecentlyUsed_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ std::array<Color, 4> colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN};
+
+ std::array<sp<GraphicBuffer>, 70> buffers;
+
+ size_t idx = 0;
+ for (auto& buffer : buffers) {
+ buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ Color color = colors[idx % colors.size()];
+ fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
+ idx++;
+ }
+
+ // Set each buffer twice. The first time adds it to the cache, the second time tests that the
+ // cache is working.
+ idx = 0;
+ for (auto& buffer : buffers) {
+ for (int i = 0; i < 2; i++) {
+ Transaction().setBuffer(layer, buffer).apply();
+
+ Color color = colors[idx % colors.size()];
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), color);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+ idx++;
+ }
+}
+
+TEST_F(LayerRenderTypeTransactionTest, SetBufferCaching_DestroyedBuffer_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ std::array<Color, 4> colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN};
+
+ std::array<sp<GraphicBuffer>, 65> buffers;
+
+ size_t idx = 0;
+ for (auto& buffer : buffers) {
+ buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ Color color = colors[idx % colors.size()];
+ fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
+ idx++;
+ }
+
+ // Set each buffer twice. The first time adds it to the cache, the second time tests that the
+ // cache is working.
+ idx = 0;
+ for (auto& buffer : buffers) {
+ for (int i = 0; i < 2; i++) {
+ Transaction().setBuffer(layer, buffer).apply();
+
+ Color color = colors[idx % colors.size()];
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), color);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+ if (idx == 0) {
+ buffers[0].clear();
+ }
+ idx++;
+ }
+}
+
TEST_P(LayerRenderTypeTransactionTest, SetTransformRotate90_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
@@ -2623,143 +2734,6 @@
Transaction().setSidebandStream(layer, nullptr).apply();
}
-TEST_F(LayerTransactionTest, CacheBuffer_BufferState) {
- sp<GraphicBuffer> buffer =
- new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
-
- int32_t bufferId = -1;
- ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId));
- ASSERT_GE(bufferId, 0);
-
- ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId));
-}
-
-TEST_F(LayerTransactionTest, CacheBuffers_BufferState) {
- std::vector<int32_t> bufferIds;
- int32_t bufferCount = 20;
-
- for (int i = 0; i < bufferCount; i++) {
- sp<GraphicBuffer> buffer =
- new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
- int32_t bufferId = -1;
- ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId));
- if (bufferId < 0) {
- EXPECT_GE(bufferId, 0);
- break;
- }
- bufferIds.push_back(bufferId);
- }
-
- for (int32_t bufferId : bufferIds) {
- ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId));
- }
-}
-
-TEST_F(LayerTransactionTest, CacheBufferInvalid_BufferState) {
- sp<GraphicBuffer> buffer = nullptr;
-
- int32_t bufferId = -1;
- ASSERT_NE(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId));
- ASSERT_LT(bufferId, 0);
-}
-
-TEST_F(LayerTransactionTest, UncacheBufferTwice_BufferState) {
- sp<GraphicBuffer> buffer =
- new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
-
- int32_t bufferId = -1;
- ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId));
- ASSERT_GE(bufferId, 0);
-
- ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId));
- mClient->uncacheBuffer(bufferId);
-}
-
-TEST_F(LayerTransactionTest, UncacheBufferInvalidId_BufferState) {
- mClient->uncacheBuffer(-1);
- mClient->uncacheBuffer(0);
- mClient->uncacheBuffer(1);
- mClient->uncacheBuffer(5);
- mClient->uncacheBuffer(1000);
-}
-
-TEST_F(LayerTransactionTest, SetCachedBuffer_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
- sp<GraphicBuffer> buffer =
- new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
-
- fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
-
- int32_t bufferId = -1;
- ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId));
- ASSERT_GE(bufferId, 0);
-
- Transaction().setCachedBuffer(layer, bufferId).apply();
-
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
- shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
-
- ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId));
-}
-
-TEST_F(LayerTransactionTest, SetCachedBufferDelayed_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
- sp<GraphicBuffer> cachedBuffer =
- new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
- int32_t bufferId = -1;
- ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(cachedBuffer, &bufferId));
- ASSERT_GE(bufferId, 0);
-
- sp<GraphicBuffer> buffer =
- new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
- fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::BLUE);
- Transaction().setBuffer(layer, buffer).apply();
- {
- SCOPED_TRACE("Uncached buffer");
-
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
- shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
- }
-
- fillGraphicBufferColor(cachedBuffer, Rect(0, 0, 32, 32), Color::RED);
- Transaction().setCachedBuffer(layer, bufferId).apply();
- {
- SCOPED_TRACE("Cached buffer");
-
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
- shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
- }
-
- ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId));
-}
-
TEST_F(LayerTransactionTest, ReparentToSelf) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));