Adding an image cache to be behind drawLayers.
This is intended to replace the shadow GLImage array in BufferQueueLayer, since
I think this is simpler, and I don't fully trust BufferLayerConsumer's locking
model so that we could safely hold a unique_ptr<GLImage> there while passing a
pointer to RenderEngine::drawLayers.
Also, putting RenderEngine behind a binderizable interface is a bit of
a stretch goal for profiling, so EGLImage operations will need to be
behind the interface.
Bug: 118461793
Change-Id: Ibde79abd722ecb48ddf1288bc27008e07e1dc0c4
Test: librenderengine_test
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 2915bb8..e92b6e7 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -608,7 +608,17 @@
}
status_t GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer,
- sp<Fence> bufferFence) {
+ sp<Fence> bufferFence, bool readCache,
+ bool persistCache) {
+ if (readCache) {
+ auto cachedImage = mImageCache.find(buffer->getId());
+
+ if (cachedImage != mImageCache.end()) {
+ bindExternalTextureImage(texName, *cachedImage->second);
+ return NO_ERROR;
+ }
+ }
+
std::unique_ptr<Image> newImage = createImage();
bool created = newImage->setNativeWindowBuffer(buffer->getNativeBuffer(),
@@ -644,9 +654,35 @@
}
}
+ // We don't always want to persist to the cache, e.g. on older devices we
+ // might bind for synchronization purpoeses, but that might leak if we never
+ // call drawLayers again, so it's just better to recreate the image again
+ // if needed when we draw.
+ if (persistCache) {
+ mImageCache.insert(std::make_pair(buffer->getId(), std::move(newImage)));
+ }
+
return NO_ERROR;
}
+void GLESRenderEngine::evictImages(const std::vector<LayerSettings>& layers) {
+ // destroy old image references that we're not going to draw with.
+ std::unordered_set<uint64_t> bufIds;
+ for (auto layer : layers) {
+ if (layer.source.buffer.buffer != nullptr) {
+ bufIds.emplace(layer.source.buffer.buffer->getId());
+ }
+ }
+
+ for (auto it = mImageCache.begin(); it != mImageCache.end();) {
+ if (bufIds.count(it->first) == 0) {
+ it = mImageCache.erase(it);
+ } else {
+ it++;
+ }
+ }
+}
+
FloatRect GLESRenderEngine::setupLayerCropping(const LayerSettings& layer, Mesh& mesh) {
// Translate win by the rounded corners rect coordinates, to have all values in
// layer coordinate space.
@@ -748,6 +784,8 @@
return fbo.getStatus();
}
+ evictImages(layers);
+
setViewportAndProjection(display.physicalDisplay, display.clip);
setOutputDataSpace(display.outputDataspace);
@@ -781,8 +819,9 @@
sp<GraphicBuffer> gBuf = layer.source.buffer.buffer;
+ bool readCache = layer.source.buffer.cacheHint == Buffer::CachingHint::USE_CACHE;
bindExternalTextureBuffer(layer.source.buffer.textureName, gBuf,
- layer.source.buffer.fence);
+ layer.source.buffer.fence, readCache, /*persistCache=*/true);
usePremultipliedAlpha = layer.source.buffer.usePremultipliedAlpha;
Texture texture(Texture::TEXTURE_EXTERNAL, layer.source.buffer.textureName);
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index b596242..e094860 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -30,6 +30,7 @@
#include <GLES2/gl2.h>
#include <renderengine/RenderEngine.h>
#include <renderengine/private/Description.h>
+#include <unordered_map>
#define EGL_NO_CONFIG ((EGLConfig)0)
@@ -133,7 +134,10 @@
// Defines the viewport, and sets the projection matrix to the projection
// defined by the clip.
void setViewportAndProjection(Rect viewport, Rect clip);
- status_t bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer, sp<Fence> fence);
+ status_t bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer, sp<Fence> fence,
+ bool readCache, bool persistCache);
+ // Evicts stale images from the buffer cache.
+ void evictImages(const std::vector<LayerSettings>& layers);
// Computes the cropping window for the layer and sets up cropping
// coordinates for the mesh.
FloatRect setupLayerCropping(const LayerSettings& layer, Mesh& mesh);
@@ -179,6 +183,9 @@
// supports sRGB, DisplayP3 color spaces.
const bool mUseColorManagement = false;
+ // Cache of GL images that we'll store per GraphicBuffer ID
+ std::unordered_map<uint64_t, std::unique_ptr<Image>> mImageCache;
+
class FlushTracer {
public:
FlushTracer(GLESRenderEngine* engine);
diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
index 4d53205..56ac714 100644
--- a/libs/renderengine/include/renderengine/LayerSettings.h
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -32,6 +32,16 @@
// Metadata describing the input buffer to render from.
struct Buffer {
+ // Hint for whether to use the Image cache or not.
+ // If NO_CACHE is specified, then upload the contents of the GraphicBuffer
+ // to the GPU, without checking against any implementation defined cache.
+ // If USE_CACHE is specified, then check against an implementation defined
+ // cache first. If there is an Image cached for the given GraphicBuffer id,
+ // then use that instead of the provided buffer contents. If there is no
+ // cached image or the RenderEngine implementation does not support caching,
+ // then use the GraphicBuffer contents.
+ enum class CachingHint { NO_CACHE, USE_CACHE };
+
// Buffer containing the image that we will render.
// If buffer == nullptr, then the rest of the fields in this struct will be
// ignored.
@@ -40,6 +50,9 @@
// Fence that will fire when the buffer is ready to be bound.
sp<Fence> fence = nullptr;
+ // Caching hint to use when uploading buffer contents.
+ CachingHint cacheHint = CachingHint::NO_CACHE;
+
// Texture identifier to bind the external texture to.
// TODO(alecmouri): This is GL-specific...make the type backend-agnostic.
uint32_t textureName = 0;