Merge "[sf] Add layer metadata to HAL classes"
diff --git a/data/etc/android.hardware.context_hub.xml b/data/etc/android.hardware.context_hub.xml
new file mode 100644
index 0000000..8133e0b
--- /dev/null
+++ b/data/etc/android.hardware.context_hub.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+
+<!-- Features for devices supporting a Context Hub. -->
+<permissions>
+ <feature name="android.hardware.context_hub" />
+</permissions>
diff --git a/data/etc/android.software.vulkan.deqp.level-2019-03-01.xml b/data/etc/android.software.vulkan.deqp.level-2019-03-01.xml
new file mode 100644
index 0000000..9c67d4a
--- /dev/null
+++ b/data/etc/android.software.vulkan.deqp.level-2019-03-01.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 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.
+-->
+
+<!-- This is the standard feature indicating that the device passes Vulkan deQP
+ tests associated with date 2019-03-01 (0x07E30301). -->
+<permissions>
+ <feature name="android.software.vulkan.deqp.level" version="132317953" />
+</permissions>
diff --git a/data/etc/android.software.vulkan.deqp.level-2020-03-01.xml b/data/etc/android.software.vulkan.deqp.level-2020-03-01.xml
new file mode 100644
index 0000000..19b269b
--- /dev/null
+++ b/data/etc/android.software.vulkan.deqp.level-2020-03-01.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 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.
+-->
+
+<!-- This is the standard feature indicating that the device passes Vulkan deQP
+ tests associated with date 2020-03-01 (0x07E40301). -->
+<permissions>
+ <feature name="android.software.vulkan.deqp.level" version="132383489" />
+</permissions>
diff --git a/include/android/bitmap.h b/include/android/bitmap.h
index d920a90..571a5ca 100644
--- a/include/android/bitmap.h
+++ b/include/android/bitmap.h
@@ -79,6 +79,14 @@
ANDROID_BITMAP_FLAGS_ALPHA_SHIFT = 0,
};
+enum {
+ /** If this bit is set in AndroidBitmapInfo.flags, the Bitmap uses the
+ * HARDWARE Config, and its AHardwareBuffer can be retrieved via
+ * AndroidBitmap_getHardwareBuffer.
+ */
+ ANDROID_BITMAP_FLAGS_IS_HARDWARE = 1 << 31,
+};
+
/** Bitmap info, see AndroidBitmap_getInfo(). */
typedef struct {
/** The bitmap width in pixels. */
@@ -90,7 +98,9 @@
/** The bitmap pixel format. See {@link AndroidBitmapFormat} */
int32_t format;
/** Two bits are used to encode alpha. Use ANDROID_BITMAP_FLAGS_ALPHA_MASK
- * and ANDROID_BITMAP_FLAGS_ALPHA_SHIFT to retrieve them. */
+ * and ANDROID_BITMAP_FLAGS_ALPHA_SHIFT to retrieve them. One bit is used
+ * to encode whether the Bitmap uses the HARDWARE Config. Use
+ * ANDROID_BITMAP_FLAGS_IS_HARDWARE to know.*/
uint32_t flags;
} AndroidBitmapInfo;
@@ -179,7 +189,7 @@
* @param size Length in bytes of data to write.
* @return Whether the operation succeeded.
*/
-typedef bool (*AndroidBitmap_compress_write_fn)(void* userContext,
+typedef bool (*AndroidBitmap_CompressWriteFunc)(void* userContext,
const void* data,
size_t size) __INTRODUCED_IN(30);
@@ -195,7 +205,7 @@
* differently depending on the
* {@link AndroidBitmapCompressFormat}.
* @param userContext User-defined data which will be passed to the supplied
- * {@link AndroidBitmap_compress_write_fn} each time it is
+ * {@link AndroidBitmap_CompressWriteFunc} each time it is
* called. May be null.
* @parm fn Function that writes the compressed data. Will be called each time
* the compressor has compressed more data that is ready to be
@@ -208,7 +218,26 @@
const void* pixels,
int32_t format, int32_t quality,
void* userContext,
- AndroidBitmap_compress_write_fn fn) __INTRODUCED_IN(30);
+ AndroidBitmap_CompressWriteFunc fn) __INTRODUCED_IN(30);
+
+struct AHardwareBuffer;
+
+/**
+ * Retrieve the native object associated with a HARDWARE Bitmap.
+ *
+ * Client must not modify it while a Bitmap is wrapping it.
+ *
+ * @param bitmap Handle to an android.graphics.Bitmap.
+ * @param outBuffer On success, is set to a pointer to the
+ * AHardwareBuffer associated with bitmap. This acquires
+ * a reference on the buffer, and the client must call
+ * AHardwareBuffer_release when finished with it.
+ * @return AndroidBitmap functions result code.
+ * ANDROID_BITMAP_RESULT_BAD_PARAMETER if bitmap is not a
+ * HARDWARE Bitmap.
+ */
+int AndroidBitmap_getHardwareBuffer(JNIEnv* env, jobject bitmap,
+ AHardwareBuffer** outBuffer) __INTRODUCED_IN(30);
#endif // __ANDROID_API__ >= 30
diff --git a/include/android/imagedecoder.h b/include/android/imagedecoder.h
index 4b6446c..469b088 100644
--- a/include/android/imagedecoder.h
+++ b/include/android/imagedecoder.h
@@ -159,6 +159,25 @@
int AImageDecoder_setUnpremultipliedRequired(AImageDecoder*, bool required) __INTRODUCED_IN(30);
/**
+ * Choose the dataspace for the output.
+ *
+ * Not supported for {@link ANDROID_BITMAP_FORMAT_A_8}, which does not support
+ * an ADataSpace.
+ *
+ * @param dataspace The {@link ADataSpace} to decode into. An ADataSpace
+ * specifies how to interpret the colors. By default,
+ * AImageDecoder will decode into the ADataSpace specified by
+ * {@link AImageDecoderHeaderInfo_getDataSpace}. If this
+ * parameter is set to a different ADataSpace, AImageDecoder
+ * will transform the output into the specified ADataSpace.
+ * @return - {@link ANDROID_IMAGE_DECODER_SUCCESS} on success
+ * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER} for a null
+ * AImageDecoder or an integer that does not correspond to an
+ * ADataSpace value.
+ */
+int AImageDecoder_setDataSpace(AImageDecoder*, int32_t dataspace) __INTRODUCED_IN(30);
+
+/**
* Specify the output size for a decoded image.
*
* Future calls to {@link AImageDecoder_decodeImage} will sample or scale the
@@ -179,6 +198,28 @@
*/
int AImageDecoder_setTargetSize(AImageDecoder*, int width, int height) __INTRODUCED_IN(30);
+
+/**
+ * Compute the dimensions to use for a given sampleSize.
+ *
+ * Although AImageDecoder can scale to an arbitrary target size (see
+ * {@link AImageDecoder_setTargetSize}), some sizes may be more efficient than
+ * others. This computes the most efficient target size to use to reach a
+ * particular sampleSize.
+ *
+ * @param sampleSize A subsampling rate of the original image. Must be greater
+ * than or equal to 1. A sampleSize of 2 means to skip every
+ * other pixel/line, resulting in a width and height that are
+ * 1/2 of the original dimensions, with 1/4 the number of
+ * pixels.
+ * @param width Out parameter for the width sampled by sampleSize, and rounded
+ * direction that the decoder can do most efficiently.
+ * @param height Out parameter for the height sampled by sampleSize, and rounded
+ * direction that the decoder can do most efficiently.
+ * @return ANDROID_IMAGE_DECODER result code.
+ */
+int AImageDecoder_computeSampledSize(const AImageDecoder*, int sampleSize,
+ int* width, int* height) __INTRODUCED_IN(30);
/**
* Specify how to crop the output after scaling (if any).
*
@@ -261,6 +302,25 @@
const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
/**
+ * Report the dataspace the AImageDecoder will decode to by default.
+ * AImageDecoder will try to choose one that is sensible for the
+ * image and the system. Note that this may not exactly match the ICC
+ * profile (or other color information) stored in the encoded image.
+ *
+ * @return The {@link ADataSpace} most closely representing the way the colors
+ * are encoded (or {@link ADATASPACE_UNKNOWN} if there is not an
+ * approximate ADataSpace). This specifies how to interpret the colors
+ * in the decoded image, unless {@link AImageDecoder_setDataSpace} is
+ * called to decode to a different ADataSpace.
+ *
+ * Note that ADataSpace only exposes a few values. This may return
+ * ADATASPACE_UNKNOWN, even for Named ColorSpaces, if they have no
+ * corresponding ADataSpace.
+ */
+int32_t AImageDecoderHeaderInfo_getDataSpace(
+ const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
+
+/**
* Return the minimum stride that can be used, taking the specified
* (or default) (possibly scaled) width, crop rect and
* {@link AndroidBitmapFormat} into account.
diff --git a/libs/gui/OWNERS b/libs/gui/OWNERS
index 274153c..c13401d 100644
--- a/libs/gui/OWNERS
+++ b/libs/gui/OWNERS
@@ -1,3 +1,6 @@
+adyabr@google.com
+akrulec@google.com
+alecmouri@google.com
jessehall@google.com
jwcai@google.com
lpy@google.com
@@ -6,3 +9,4 @@
racarr@google.com
steventhomas@google.com
stoza@google.com
+vhau@google.com
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 09659fe..e257704 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -960,7 +960,7 @@
}
status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
- const std::vector<LayerSettings>& layers,
+ const std::vector<const LayerSettings*>& layers,
ANativeWindowBuffer* const buffer,
const bool useFramebufferCache, base::unique_fd&& bufferFence,
base::unique_fd* drawFence) {
@@ -985,9 +985,9 @@
// Blurs in multiple layers are not supported, given the cost of the shader.
const LayerSettings* blurLayer = nullptr;
if (CC_LIKELY(mBlurFilter != nullptr)) {
- for (auto const& layer : layers) {
- if (layer.backgroundBlurRadius > 0) {
- blurLayer = &layer;
+ for (auto const layer : layers) {
+ if (layer->backgroundBlurRadius > 0) {
+ blurLayer = layer;
}
}
}
@@ -1035,9 +1035,9 @@
.setTexCoords(2 /* size */)
.setCropCoords(2 /* size */)
.build();
- for (auto const& layer : layers) {
- if (blurLayer == &layer) {
- auto status = mBlurFilter->prepare(layer.backgroundBlurRadius);
+ for (auto const layer : layers) {
+ if (blurLayer == layer) {
+ auto status = mBlurFilter->prepare(layer->backgroundBlurRadius);
if (status != NO_ERROR) {
ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).",
buffer->handle);
@@ -1065,40 +1065,40 @@
}
}
- mState.maxMasteringLuminance = layer.source.buffer.maxMasteringLuminance;
- mState.maxContentLuminance = layer.source.buffer.maxContentLuminance;
- mState.projectionMatrix = projectionMatrix * layer.geometry.positionTransform;
+ mState.maxMasteringLuminance = layer->source.buffer.maxMasteringLuminance;
+ mState.maxContentLuminance = layer->source.buffer.maxContentLuminance;
+ mState.projectionMatrix = projectionMatrix * layer->geometry.positionTransform;
- const FloatRect bounds = layer.geometry.boundaries;
+ const FloatRect bounds = layer->geometry.boundaries;
Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
position[0] = vec2(bounds.left, bounds.top);
position[1] = vec2(bounds.left, bounds.bottom);
position[2] = vec2(bounds.right, bounds.bottom);
position[3] = vec2(bounds.right, bounds.top);
- setupLayerCropping(layer, mesh);
- setColorTransform(display.colorTransform * layer.colorTransform);
+ setupLayerCropping(*layer, mesh);
+ setColorTransform(display.colorTransform * layer->colorTransform);
bool usePremultipliedAlpha = true;
bool disableTexture = true;
bool isOpaque = false;
- if (layer.source.buffer.buffer != nullptr) {
+ if (layer->source.buffer.buffer != nullptr) {
disableTexture = false;
- isOpaque = layer.source.buffer.isOpaque;
+ isOpaque = layer->source.buffer.isOpaque;
- sp<GraphicBuffer> gBuf = layer.source.buffer.buffer;
- bindExternalTextureBuffer(layer.source.buffer.textureName, gBuf,
- layer.source.buffer.fence);
+ sp<GraphicBuffer> gBuf = layer->source.buffer.buffer;
+ bindExternalTextureBuffer(layer->source.buffer.textureName, gBuf,
+ layer->source.buffer.fence);
- usePremultipliedAlpha = layer.source.buffer.usePremultipliedAlpha;
- Texture texture(Texture::TEXTURE_EXTERNAL, layer.source.buffer.textureName);
- mat4 texMatrix = layer.source.buffer.textureTransform;
+ usePremultipliedAlpha = layer->source.buffer.usePremultipliedAlpha;
+ Texture texture(Texture::TEXTURE_EXTERNAL, layer->source.buffer.textureName);
+ mat4 texMatrix = layer->source.buffer.textureTransform;
texture.setMatrix(texMatrix.asArray());
- texture.setFiltering(layer.source.buffer.useTextureFiltering);
+ texture.setFiltering(layer->source.buffer.useTextureFiltering);
texture.setDimensions(gBuf->getWidth(), gBuf->getHeight());
- setSourceY410BT2020(layer.source.buffer.isY410BT2020);
+ setSourceY410BT2020(layer->source.buffer.isY410BT2020);
renderengine::Mesh::VertexArray<vec2> texCoords(mesh.getTexCoordArray<vec2>());
texCoords[0] = vec2(0.0, 0.0);
@@ -1108,32 +1108,32 @@
setupLayerTexturing(texture);
}
- const half3 solidColor = layer.source.solidColor;
- const half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer.alpha);
+ const half3 solidColor = layer->source.solidColor;
+ const half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer->alpha);
// Buffer sources will have a black solid color ignored in the shader,
// so in that scenario the solid color passed here is arbitrary.
setupLayerBlending(usePremultipliedAlpha, isOpaque, disableTexture, color,
- layer.geometry.roundedCornersRadius);
- if (layer.disableBlending) {
+ layer->geometry.roundedCornersRadius);
+ if (layer->disableBlending) {
glDisable(GL_BLEND);
}
- setSourceDataSpace(layer.sourceDataspace);
+ setSourceDataSpace(layer->sourceDataspace);
- if (layer.shadow.length > 0.0f) {
- handleShadow(layer.geometry.boundaries, layer.geometry.roundedCornersRadius,
- layer.shadow);
+ if (layer->shadow.length > 0.0f) {
+ handleShadow(layer->geometry.boundaries, layer->geometry.roundedCornersRadius,
+ layer->shadow);
}
// We only want to do a special handling for rounded corners when having rounded corners
// is the only reason it needs to turn on blending, otherwise, we handle it like the
// usual way since it needs to turn on blending anyway.
- else if (layer.geometry.roundedCornersRadius > 0.0 && color.a >= 1.0f && isOpaque) {
- handleRoundedCorners(display, layer, mesh);
+ else if (layer->geometry.roundedCornersRadius > 0.0 && color.a >= 1.0f && isOpaque) {
+ handleRoundedCorners(display, *layer, mesh);
} else {
drawMesh(mesh);
}
// Cleanup if there's a buffer source
- if (layer.source.buffer.buffer != nullptr) {
+ if (layer->source.buffer.buffer != nullptr) {
disableBlending();
setSourceY410BT2020(false);
disableTexturing();
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 547235a..45c85de 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -71,7 +71,8 @@
bool isProtected() const override { return mInProtectedContext; }
bool supportsProtectedContent() const override;
bool useProtectedContext(bool useProtectedContext) override;
- status_t drawLayers(const DisplaySettings& display, const std::vector<LayerSettings>& layers,
+ status_t drawLayers(const DisplaySettings& display,
+ const std::vector<const LayerSettings*>& layers,
ANativeWindowBuffer* buffer, const bool useFramebufferCache,
base::unique_fd&& bufferFence, base::unique_fd* drawFence) override;
diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
index 3dc198f..95e9367 100644
--- a/libs/renderengine/include/renderengine/LayerSettings.h
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -52,7 +52,7 @@
// Transform matrix to apply to texture coordinates.
mat4 textureTransform = mat4();
- // Wheteher to use pre-multiplied alpha
+ // Whether to use pre-multiplied alpha.
bool usePremultipliedAlpha = true;
// Override flag that alpha for each pixel in the buffer *must* be 1.0.
@@ -153,6 +153,8 @@
int backgroundBlurRadius = 0;
};
+// Keep in sync with custom comparison function in
+// compositionengine/impl/ClientCompositionRequestCache.cpp
static inline bool operator==(const Buffer& lhs, const Buffer& rhs) {
return lhs.buffer == rhs.buffer && lhs.fence == rhs.fence &&
lhs.textureName == rhs.textureName &&
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index e3c2d84..46f3fc6 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -154,7 +154,7 @@
// @return An error code indicating whether drawing was successful. For
// now, this always returns NO_ERROR.
virtual status_t drawLayers(const DisplaySettings& display,
- const std::vector<LayerSettings>& layers,
+ const std::vector<const LayerSettings*>& layers,
ANativeWindowBuffer* buffer, const bool useFramebufferCache,
base::unique_fd&& bufferFence, base::unique_fd* drawFence) = 0;
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index 0750e86..3358c69 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -56,7 +56,7 @@
MOCK_CONST_METHOD0(supportsProtectedContent, bool());
MOCK_METHOD1(useProtectedContext, bool(bool));
MOCK_METHOD6(drawLayers,
- status_t(const DisplaySettings&, const std::vector<LayerSettings>&,
+ status_t(const DisplaySettings&, const std::vector<const LayerSettings*>&,
ANativeWindowBuffer*, const bool, base::unique_fd&&, base::unique_fd*));
};
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index e676740..afcbc50 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -249,7 +249,8 @@
}
void invokeDraw(renderengine::DisplaySettings settings,
- std::vector<renderengine::LayerSettings> layers, sp<GraphicBuffer> buffer) {
+ std::vector<const renderengine::LayerSettings*> layers,
+ sp<GraphicBuffer> buffer) {
base::unique_fd fence;
status_t status = sRE->drawLayers(settings, layers, buffer->getNativeBuffer(), true,
base::unique_fd(), &fence);
@@ -269,7 +270,7 @@
void drawEmptyLayers() {
renderengine::DisplaySettings settings;
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
// Meaningless buffer since we don't do any drawing
sp<GraphicBuffer> buffer = new GraphicBuffer();
invokeDraw(settings, layers, buffer);
@@ -440,14 +441,14 @@
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
layer.geometry.boundaries = fullscreenRect().toFloatRect();
SourceVariant::fillColor(layer, r, g, b, this);
layer.alpha = a;
- layers.push_back(layer);
+ layers.push_back(&layer);
invokeDraw(settings, layers, mBuffer);
}
@@ -482,14 +483,14 @@
settings.physicalDisplay = offsetRect();
settings.clip = offsetRectAtZero();
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
layer.geometry.boundaries = offsetRectAtZero().toFloatRect();
SourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
layer.alpha = 1.0f;
- layers.push_back(layer);
+ layers.push_back(&layer);
invokeDraw(settings, layers, mBuffer);
}
@@ -515,7 +516,7 @@
settings.clip = Rect(2, 2);
settings.globalTransform = transform;
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layerOne;
Rect rectOne(0, 0, 1, 1);
@@ -535,9 +536,9 @@
SourceVariant::fillColor(layerThree, 0.0f, 0.0f, 1.0f, this);
layerThree.alpha = 1.0f;
- layers.push_back(layerOne);
- layers.push_back(layerTwo);
- layers.push_back(layerThree);
+ layers.push_back(&layerOne);
+ layers.push_back(&layerTwo);
+ layers.push_back(&layerThree);
invokeDraw(settings, layers, mBuffer);
}
@@ -616,7 +617,7 @@
// Here logical space is 2x2
settings.clip = Rect(2, 2);
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
layer.geometry.boundaries = Rect(1, 1).toFloatRect();
@@ -626,7 +627,7 @@
layer.source.solidColor = half3(1.0f, 0.0f, 0.0f);
layer.alpha = 1.0f;
- layers.push_back(layer);
+ layers.push_back(&layer);
invokeDraw(settings, layers, mBuffer);
}
@@ -647,7 +648,7 @@
settings.physicalDisplay = fullscreenRect();
settings.clip = Rect(1, 1);
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
layer.geometry.boundaries = Rect(1, 1).toFloatRect();
@@ -663,7 +664,7 @@
layer.alpha = 1.0f;
layer.geometry.boundaries = Rect(1, 1).toFloatRect();
- layers.push_back(layer);
+ layers.push_back(&layer);
invokeDraw(settings, layers, mBuffer);
}
@@ -680,7 +681,7 @@
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
layer.geometry.boundaries = fullscreenRect().toFloatRect();
@@ -689,7 +690,7 @@
SourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
layer.alpha = 1.0f;
- layers.push_back(layer);
+ layers.push_back(&layer);
invokeDraw(settings, layers, mBuffer);
}
@@ -726,26 +727,26 @@
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings backgroundLayer;
backgroundLayer.geometry.boundaries = fullscreenRect().toFloatRect();
SourceVariant::fillColor(backgroundLayer, 0.0f, 1.0f, 0.0f, this);
backgroundLayer.alpha = 1.0f;
- layers.push_back(backgroundLayer);
+ layers.push_back(&backgroundLayer);
renderengine::LayerSettings leftLayer;
leftLayer.geometry.boundaries =
Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT).toFloatRect();
SourceVariant::fillColor(leftLayer, 1.0f, 0.0f, 0.0f, this);
leftLayer.alpha = 1.0f;
- layers.push_back(leftLayer);
+ layers.push_back(&leftLayer);
renderengine::LayerSettings blurLayer;
blurLayer.geometry.boundaries = fullscreenRect().toFloatRect();
blurLayer.backgroundBlurRadius = blurRadius;
blurLayer.alpha = 0;
- layers.push_back(blurLayer);
+ layers.push_back(&blurLayer);
invokeDraw(settings, layers, mBuffer);
@@ -761,7 +762,7 @@
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
- std::vector<renderengine::LayerSettings> layersFirst;
+ std::vector<const renderengine::LayerSettings*> layersFirst;
renderengine::LayerSettings layerOne;
layerOne.geometry.boundaries =
@@ -769,14 +770,14 @@
SourceVariant::fillColor(layerOne, 1.0f, 0.0f, 0.0f, this);
layerOne.alpha = 0.2;
- layersFirst.push_back(layerOne);
+ layersFirst.push_back(&layerOne);
invokeDraw(settings, layersFirst, mBuffer);
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3), 51, 0, 0, 51);
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3 + 1, DEFAULT_DISPLAY_HEIGHT / 3 + 1,
DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
0, 0, 0, 0);
- std::vector<renderengine::LayerSettings> layersSecond;
+ std::vector<const renderengine::LayerSettings*> layersSecond;
renderengine::LayerSettings layerTwo;
layerTwo.geometry.boundaries =
FloatRect(DEFAULT_DISPLAY_WIDTH / 3.0, DEFAULT_DISPLAY_HEIGHT / 3.0,
@@ -784,7 +785,7 @@
SourceVariant::fillColor(layerTwo, 0.0f, 1.0f, 0.0f, this);
layerTwo.alpha = 1.0f;
- layersSecond.push_back(layerTwo);
+ layersSecond.push_back(&layerTwo);
invokeDraw(settings, layersSecond, mBuffer);
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3), 0, 0, 0, 0);
@@ -798,7 +799,7 @@
settings.physicalDisplay = fullscreenRect();
settings.clip = Rect(1, 1);
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
// Here will allocate a checker board texture, but transform texture
@@ -833,7 +834,7 @@
layer.alpha = 1.0f;
layer.geometry.boundaries = Rect(1, 1).toFloatRect();
- layers.push_back(layer);
+ layers.push_back(&layer);
invokeDraw(settings, layers, mBuffer);
}
@@ -849,7 +850,7 @@
// Here logical space is 1x1
settings.clip = Rect(1, 1);
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1);
@@ -872,7 +873,7 @@
layer.alpha = 0.5f;
layer.geometry.boundaries = Rect(1, 1).toFloatRect();
- layers.push_back(layer);
+ layers.push_back(&layer);
invokeDraw(settings, layers, mBuffer);
}
@@ -888,7 +889,7 @@
// Here logical space is 1x1
settings.clip = Rect(1, 1);
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1);
@@ -911,7 +912,7 @@
layer.alpha = 0.5f;
layer.geometry.boundaries = Rect(1, 1).toFloatRect();
- layers.push_back(layer);
+ layers.push_back(&layer);
invokeDraw(settings, layers, mBuffer);
}
@@ -928,10 +929,10 @@
settings.clip = Rect(4, 4);
settings.globalTransform = mat4::scale(vec4(2, 4, 0, 1));
settings.clearRegion = Region(Rect(1, 1));
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
// dummy layer, without bounds should not render anything
renderengine::LayerSettings layer;
- layers.push_back(layer);
+ layers.push_back(&layer);
invokeDraw(settings, layers, mBuffer);
}
@@ -952,7 +953,7 @@
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
// add background layer
renderengine::LayerSettings bgLayer;
@@ -960,20 +961,20 @@
ColorSourceVariant::fillColor(bgLayer, backgroundColor.r / 255.0f, backgroundColor.g / 255.0f,
backgroundColor.b / 255.0f, this);
bgLayer.alpha = backgroundColor.a / 255.0f;
- layers.push_back(bgLayer);
+ layers.push_back(&bgLayer);
// add shadow layer
renderengine::LayerSettings shadowLayer;
shadowLayer.geometry.boundaries = castingLayer.geometry.boundaries;
shadowLayer.alpha = castingLayer.alpha;
shadowLayer.shadow = shadow;
- layers.push_back(shadowLayer);
+ layers.push_back(&shadowLayer);
// add layer casting the shadow
renderengine::LayerSettings layer = castingLayer;
SourceVariant::fillColor(layer, casterColor.r / 255.0f, casterColor.g / 255.0f,
casterColor.b / 255.0f, this);
- layers.push_back(layer);
+ layers.push_back(&layer);
invokeDraw(settings, layers, mBuffer);
}
@@ -984,11 +985,11 @@
TEST_F(RenderEngineTest, drawLayers_nullOutputBuffer) {
renderengine::DisplaySettings settings;
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
layer.geometry.boundaries = fullscreenRect().toFloatRect();
BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
- layers.push_back(layer);
+ layers.push_back(&layer);
base::unique_fd fence;
status_t status = sRE->drawLayers(settings, layers, nullptr, true, base::unique_fd(), &fence);
@@ -1000,12 +1001,12 @@
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
layer.geometry.boundaries = fullscreenRect().toFloatRect();
BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
layer.alpha = 1.0;
- layers.push_back(layer);
+ layers.push_back(&layer);
status_t status = sRE->drawLayers(settings, layers, mBuffer->getNativeBuffer(), true,
base::unique_fd(), nullptr);
@@ -1019,12 +1020,12 @@
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
layer.geometry.boundaries = fullscreenRect().toFloatRect();
BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
layer.alpha = 1.0;
- layers.push_back(layer);
+ layers.push_back(&layer);
status_t status = sRE->drawLayers(settings, layers, mBuffer->getNativeBuffer(), false,
base::unique_fd(), nullptr);
@@ -1223,13 +1224,13 @@
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
- std::vector<renderengine::LayerSettings> layers;
+ std::vector<const renderengine::LayerSettings*> layers;
renderengine::LayerSettings layer;
layer.geometry.boundaries = fullscreenRect().toFloatRect();
BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
- layers.push_back(layer);
+ layers.push_back(&layer);
invokeDraw(settings, layers, mBuffer);
uint64_t bufferId = layer.source.buffer.buffer->getId();
EXPECT_TRUE(sRE->isImageCachedForTesting(bufferId));
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 7845cab..35d0215 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -144,11 +144,12 @@
return inverse(tr);
}
-std::optional<renderengine::LayerSettings> BufferLayer::prepareClientComposition(
+std::optional<compositionengine::LayerFE::LayerSettings> BufferLayer::prepareClientComposition(
compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
ATRACE_CALL();
- auto result = Layer::prepareClientComposition(targetSettings);
+ std::optional<compositionengine::LayerFE::LayerSettings> result =
+ Layer::prepareClientComposition(targetSettings);
if (!result) {
return result;
}
@@ -183,7 +184,7 @@
bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) ||
(isSecure() && !targetSettings.isSecure);
const State& s(getDrawingState());
- auto& layer = *result;
+ LayerFE::LayerSettings& layer = *result;
if (!blackOutLayer) {
layer.source.buffer.buffer = mBufferInfo.mBuffer;
layer.source.buffer.isOpaque = isOpaque(s);
@@ -199,6 +200,9 @@
layer.source.buffer.maxContentLuminance = hasCta861_3
? mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel
: defaultMaxContentLuminance;
+ layer.frameNumber = mCurrentFrameNumber;
+ layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getId() : 0;
+
// TODO: we could be more subtle with isFixedSize()
const bool useFiltering = targetSettings.needsFiltering || mNeedsFiltering || isFixedSize();
@@ -264,9 +268,11 @@
// layer.
layer.source.buffer.buffer = nullptr;
layer.alpha = 1.0;
+ layer.frameNumber = 0;
+ layer.bufferId = 0;
}
- return result;
+ return layer;
}
bool BufferLayer::isHdrY410() const {
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 5f5532e..b2398a8 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -177,7 +177,7 @@
*/
bool onPreComposition(nsecs_t) override;
void latchPerFrameState(compositionengine::LayerFECompositionState&) const override;
- std::optional<renderengine::LayerSettings> prepareClientComposition(
+ std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition(
compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
// Loads the corresponding system property once per process
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index c173c66..287fe89 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -239,6 +239,8 @@
mReleasePreviousBuffer = true;
}
+ mFrameCounter++;
+
mCurrentState.buffer = buffer;
mCurrentState.clientCacheId = clientCacheId;
mCurrentState.modified = true;
@@ -496,6 +498,8 @@
handle->latchTime = latchTime;
}
+ mFrameNumber = mFrameCounter;
+
if (!SyncFeatures::getInstance().useNativeFenceSync()) {
// Bind the new buffer to the GL texture.
//
@@ -557,8 +561,6 @@
compositionState.buffer = mBufferInfo.mBuffer;
compositionState.bufferSlot = mBufferInfo.mBufferSlot;
compositionState.acquireFence = mBufferInfo.mFence;
-
- mFrameNumber++;
}
void BufferStateLayer::HwcSlotGenerator::bufferErased(const client_cache_t& clientCacheId) {
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 574bc51..9427283 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -141,7 +141,8 @@
std::atomic<bool> mSidebandStreamChanged{false};
- mutable uint32_t mFrameNumber{0};
+ mutable uint64_t mFrameNumber{0};
+ uint64_t mFrameCounter{0};
sp<Fence> mPreviousReleaseFence;
uint64_t mPreviousBufferId = 0;
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index 6aea88a..04854d0 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -50,7 +50,7 @@
ColorLayer::~ColorLayer() = default;
-std::optional<renderengine::LayerSettings> ColorLayer::prepareClientComposition(
+std::optional<compositionengine::LayerFE::LayerSettings> ColorLayer::prepareClientComposition(
compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
auto result = Layer::prepareClientComposition(targetSettings);
if (!result) {
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index 634a800..9246eb2 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -46,7 +46,7 @@
* compositionengine::LayerFE overrides
*/
void latchPerFrameState(compositionengine::LayerFECompositionState&) const override;
- std::optional<renderengine::LayerSettings> prepareClientComposition(
+ std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition(
compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
std::shared_ptr<compositionengine::Layer> mCompositionLayer;
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index 42d9875..a634f2f 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -44,6 +44,7 @@
name: "libcompositionengine",
defaults: ["libcompositionengine_defaults"],
srcs: [
+ "src/ClientCompositionRequestCache.cpp",
"src/CompositionEngine.cpp",
"src/Display.cpp",
"src/DisplayColorProfile.cpp",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
index 9193dc0..a38d1f3 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
@@ -52,6 +52,10 @@
// Creates a render surface for the display
virtual void createRenderSurface(const RenderSurfaceCreationArgs&) = 0;
+ // Creates a cache to cache duplicate client composition requests and skip
+ // similar requests if needed.
+ virtual void createClientCompositionCache(uint32_t cacheSize) = 0;
+
protected:
~Display() = default;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index e432b1c..f34509f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -89,16 +89,26 @@
Region& clearRegion;
};
+ // A superset of LayerSettings required by RenderEngine to compose a layer
+ // and buffer info to determine duplicate client composition requests.
+ struct LayerSettings : renderengine::LayerSettings {
+ // Currently latched buffer if, 0 if invalid.
+ uint64_t bufferId = 0;
+
+ // Currently latched frame number, 0 if invalid.
+ uint64_t frameNumber = 0;
+ };
+
// Returns the LayerSettings to pass to RenderEngine::drawLayers, or
// nullopt_t if the layer does not render
- virtual std::optional<renderengine::LayerSettings> prepareClientComposition(
+ virtual std::optional<LayerSettings> prepareClientComposition(
ClientCompositionTargetSettings&) = 0;
// Returns the LayerSettings used to draw shadows around a layer. It is passed
// to RenderEngine::drawLayers. Returns nullopt_t if the layer does not render
// shadows.
- virtual std::optional<renderengine::LayerSettings> prepareShadowClientComposition(
- const renderengine::LayerSettings& layerSettings, const Rect& displayViewport,
+ virtual std::optional<LayerSettings> prepareShadowClientComposition(
+ const LayerSettings& layerSettings, const Rect& displayViewport,
ui::Dataspace outputDataspace) = 0;
// Called after the layer is displayed to update the presentation fence
@@ -125,6 +135,13 @@
lhs.clearRegion.hasSameRects(rhs.clearRegion);
}
+static inline bool operator==(const LayerFE::LayerSettings& lhs,
+ const LayerFE::LayerSettings& rhs) {
+ return static_cast<const renderengine::LayerSettings&>(lhs) ==
+ static_cast<const renderengine::LayerSettings&>(rhs) &&
+ lhs.bufferId == rhs.bufferId && lhs.frameNumber == rhs.frameNumber;
+}
+
// Defining PrintTo helps with Google Tests.
static inline void PrintTo(const LayerFE::ClientCompositionTargetSettings& settings,
::std::ostream* os) {
@@ -140,5 +157,13 @@
*os << "\n}";
}
+static inline void PrintTo(const LayerFE::LayerSettings& settings, ::std::ostream* os) {
+ *os << "LayerFE::LayerSettings{";
+ PrintTo(static_cast<const renderengine::LayerSettings&>(settings), os);
+ *os << "\n .bufferId = " << settings.bufferId;
+ *os << "\n .frameNumber = " << settings.frameNumber;
+ *os << "\n}";
+}
+
} // namespace compositionengine
} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 076fdad..a5da0b1 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -162,7 +162,7 @@
virtual void setCompositionEnabled(bool) = 0;
// Sets the projection state to use
- virtual void setProjection(const ui::Transform&, int32_t orientation, const Rect& frame,
+ virtual void setProjection(const ui::Transform&, uint32_t orientation, const Rect& frame,
const Rect& viewport, const Rect& scissor, bool needsFiltering) = 0;
// Sets the bounds to use
virtual void setBounds(const ui::Size&) = 0;
@@ -271,12 +271,13 @@
virtual void chooseCompositionStrategy() = 0;
virtual bool getSkipColorTransform() const = 0;
virtual FrameFences presentAndGetFrameFences() = 0;
- virtual std::vector<renderengine::LayerSettings> generateClientCompositionRequests(
+ virtual std::vector<LayerFE::LayerSettings> generateClientCompositionRequests(
bool supportsProtectedContent, Region& clearRegion, ui::Dataspace outputDataspace) = 0;
virtual void appendRegionFlashRequests(
const Region& flashRegion,
- std::vector<renderengine::LayerSettings>& clientCompositionLayers) = 0;
+ std::vector<LayerFE::LayerSettings>& clientCompositionLayers) = 0;
virtual void setExpensiveRenderingExpected(bool enabled) = 0;
+ virtual void cacheClientCompositionRequests(uint32_t cacheSize) = 0;
};
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/ClientCompositionRequestCache.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/ClientCompositionRequestCache.h
new file mode 100644
index 0000000..c14a6e8
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/ClientCompositionRequestCache.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <deque>
+
+#include <compositionengine/LayerFE.h>
+#include <renderengine/DisplaySettings.h>
+#include <renderengine/LayerSettings.h>
+
+namespace android {
+
+namespace compositionengine::impl {
+
+// The cache is used to skip duplicate client composition requests. We do so by keeping track
+// of every composition request and the buffer that the request is rendered into. During the
+// next composition request, if the request matches what was rendered into the buffer, then
+// we can skip of the request, pass back an empty fence, and let HWC use the previous render
+// result.
+//
+// The cache is a mapping of the RenderSurface buffer id (unique per process) and a snapshot of
+// the composition request. We need to make sure the request, including the order of the
+// layers, do not change from call to call. The snapshot removes strong references to the
+// client buffer id so we don't extend the lifetime of the buffer by storing it in the cache.
+class ClientCompositionRequestCache {
+public:
+ explicit ClientCompositionRequestCache(uint32_t cacheSize) : mMaxCacheSize(cacheSize){};
+ ~ClientCompositionRequestCache() = default;
+ bool exists(uint64_t bufferId, const renderengine::DisplaySettings& display,
+ const std::vector<LayerFE::LayerSettings>& layerSettings) const;
+ void add(uint64_t bufferId, const renderengine::DisplaySettings& display,
+ const std::vector<LayerFE::LayerSettings>& layerSettings);
+ void remove(uint64_t bufferId);
+
+private:
+ uint32_t mMaxCacheSize;
+ struct ClientCompositionRequest {
+ renderengine::DisplaySettings display;
+ std::vector<LayerFE::LayerSettings> layerSettings;
+ ClientCompositionRequest(const renderengine::DisplaySettings& _display,
+ const std::vector<LayerFE::LayerSettings>& _layerSettings);
+ bool equals(const renderengine::DisplaySettings& _display,
+ const std::vector<LayerFE::LayerSettings>& _layerSettings) const;
+ };
+
+ // Cache of requests, keyed by corresponding GraphicBuffer ID.
+ std::deque<std::pair<uint64_t /* bufferId */, ClientCompositionRequest>> mCache;
+};
+
+} // namespace compositionengine::impl
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index ace876c..39acb37 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -60,6 +60,7 @@
void createDisplayColorProfile(
const compositionengine::DisplayColorProfileCreationArgs&) override;
void createRenderSurface(const compositionengine::RenderSurfaceCreationArgs&) override;
+ void createClientCompositionCache(uint32_t cacheSize) override;
// Internal helpers used by chooseCompositionStrategy()
using ChangedTypes = android::HWComposer::DeviceRequestedChanges::ChangedTypes;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 3a9776d..f469e62 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -18,8 +18,10 @@
#include <compositionengine/CompositionEngine.h>
#include <compositionengine/Output.h>
+#include <compositionengine/impl/ClientCompositionRequestCache.h>
#include <compositionengine/impl/OutputCompositionState.h>
-
+#include <renderengine/DisplaySettings.h>
+#include <renderengine/LayerSettings.h>
#include <memory>
#include <utility>
#include <vector>
@@ -36,7 +38,7 @@
bool isValid() const override;
std::optional<DisplayId> getDisplayId() const override;
void setCompositionEnabled(bool) override;
- void setProjection(const ui::Transform&, int32_t orientation, const Rect& frame,
+ void setProjection(const ui::Transform&, uint32_t orientation, const Rect& frame,
const Rect& viewport, const Rect& scissor, bool needsFiltering) override;
void setBounds(const ui::Size&) override;
void setLayerStackFilter(uint32_t layerStackId, bool isInternal) override;
@@ -83,6 +85,7 @@
void finishFrame(const CompositionRefreshArgs&) override;
std::optional<base::unique_fd> composeSurfaces(const Region&) override;
void postFramebuffer() override;
+ void cacheClientCompositionRequests(uint32_t) override;
// Testing
const ReleasedLayers& getReleasedLayersForTest() const;
@@ -96,11 +99,10 @@
void chooseCompositionStrategy() override;
bool getSkipColorTransform() const override;
compositionengine::Output::FrameFences presentAndGetFrameFences() override;
- std::vector<renderengine::LayerSettings> generateClientCompositionRequests(
+ std::vector<LayerFE::LayerSettings> generateClientCompositionRequests(
bool supportsProtectedContent, Region& clearRegion,
ui::Dataspace outputDataspace) override;
- void appendRegionFlashRequests(const Region&,
- std::vector<renderengine::LayerSettings>&) override;
+ void appendRegionFlashRequests(const Region&, std::vector<LayerFE::LayerSettings>&) override;
void setExpensiveRenderingExpected(bool enabled) override;
void dumpBase(std::string&) const;
@@ -128,6 +130,7 @@
ReleasedLayers mReleasedLayers;
OutputLayer* mLayerRequestingBackgroundBlur = nullptr;
+ std::unique_ptr<ClientCompositionRequestCache> mClientCompositionRequestCache;
};
// This template factory function standardizes the implementation details of the
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index 17d3d3f..34dadb5 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -45,6 +45,9 @@
// composition
bool flipClientTarget{false};
+ // If true, the current frame reused the buffer from a previous client composition
+ bool reusedClientComposition{false};
+
// If true, this output displays layers that are internal-only
bool layerStackInternal{false};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
index 57f33ae..3a4c70f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
@@ -40,6 +40,7 @@
MOCK_METHOD1(createDisplayColorProfile, void(const DisplayColorProfileCreationArgs&));
MOCK_METHOD1(createRenderSurface, void(const RenderSurfaceCreationArgs&));
+ MOCK_METHOD1(createClientCompositionCache, void(uint32_t));
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index 739490f..163e302 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -36,11 +36,10 @@
void(LayerFECompositionState&, compositionengine::LayerFE::StateSubset));
MOCK_CONST_METHOD1(latchCursorCompositionState, void(LayerFECompositionState&));
MOCK_METHOD1(prepareClientComposition,
- std::optional<renderengine::LayerSettings>(
+ std::optional<LayerSettings>(
compositionengine::LayerFE::ClientCompositionTargetSettings&));
MOCK_METHOD3(prepareShadowClientComposition,
- std::optional<renderengine::LayerSettings>(const renderengine::LayerSettings&,
- const Rect&, ui::Dataspace));
+ std::optional<LayerSettings>(const LayerSettings&, const Rect&, ui::Dataspace));
MOCK_METHOD1(onLayerDisplayed, void(const sp<Fence>&));
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index 7f5bd06..c41302d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -38,7 +38,7 @@
MOCK_METHOD1(setCompositionEnabled, void(bool));
MOCK_METHOD6(setProjection,
- void(const ui::Transform&, int32_t, const Rect&, const Rect&, const Rect&, bool));
+ void(const ui::Transform&, uint32_t, const Rect&, const Rect&, const Rect&, bool));
MOCK_METHOD1(setBounds, void(const ui::Size&));
MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool));
@@ -107,10 +107,11 @@
MOCK_METHOD0(presentAndGetFrameFences, compositionengine::Output::FrameFences());
MOCK_METHOD3(generateClientCompositionRequests,
- std::vector<renderengine::LayerSettings>(bool, Region&, ui::Dataspace));
+ std::vector<LayerFE::LayerSettings>(bool, Region&, ui::Dataspace));
MOCK_METHOD2(appendRegionFlashRequests,
- void(const Region&, std::vector<renderengine::LayerSettings>&));
+ void(const Region&, std::vector<LayerFE::LayerSettings>&));
MOCK_METHOD1(setExpensiveRenderingExpected, void(bool));
+ MOCK_METHOD1(cacheClientCompositionRequests, void(uint32_t));
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp b/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp
new file mode 100644
index 0000000..acaaf4e
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <algorithm>
+
+#include <compositionengine/impl/ClientCompositionRequestCache.h>
+#include <renderengine/DisplaySettings.h>
+#include <renderengine/LayerSettings.h>
+
+namespace android::compositionengine::impl {
+
+namespace {
+LayerFE::LayerSettings getLayerSettingsSnapshot(const LayerFE::LayerSettings& settings) {
+ LayerFE::LayerSettings snapshot = settings;
+ snapshot.source.buffer.buffer = nullptr;
+ snapshot.source.buffer.fence = nullptr;
+ return snapshot;
+}
+
+inline bool equalIgnoringSource(const renderengine::LayerSettings& lhs,
+ const renderengine::LayerSettings& rhs) {
+ return lhs.geometry == rhs.geometry && lhs.alpha == rhs.alpha &&
+ lhs.sourceDataspace == rhs.sourceDataspace &&
+ lhs.colorTransform == rhs.colorTransform &&
+ lhs.disableBlending == rhs.disableBlending && lhs.shadow == rhs.shadow;
+}
+
+inline bool equalIgnoringBuffer(const renderengine::Buffer& lhs, const renderengine::Buffer& rhs) {
+ return lhs.textureName == rhs.textureName &&
+ lhs.useTextureFiltering == rhs.useTextureFiltering &&
+ lhs.textureTransform == rhs.textureTransform &&
+ lhs.usePremultipliedAlpha == rhs.usePremultipliedAlpha &&
+ lhs.isOpaque == rhs.isOpaque && lhs.isY410BT2020 == rhs.isY410BT2020 &&
+ lhs.maxMasteringLuminance == rhs.maxMasteringLuminance &&
+ lhs.maxContentLuminance == rhs.maxContentLuminance;
+}
+
+inline bool equalIgnoringBuffer(const renderengine::LayerSettings& lhs,
+ const renderengine::LayerSettings& rhs) {
+ // compare LayerSettings without LayerSettings.PixelSource
+ return equalIgnoringSource(lhs, rhs) &&
+
+ // compare LayerSettings.PixelSource without buffer
+ lhs.source.solidColor == rhs.source.solidColor &&
+
+ // compare LayerSettings.PixelSource.Buffer without buffer & fence
+ equalIgnoringBuffer(lhs.source.buffer, rhs.source.buffer);
+}
+
+bool layerSettingsAreEqual(const LayerFE::LayerSettings& lhs, const LayerFE::LayerSettings& rhs) {
+ return lhs.bufferId == rhs.bufferId && lhs.frameNumber == rhs.frameNumber &&
+ equalIgnoringBuffer(lhs, rhs);
+}
+
+} // namespace
+
+ClientCompositionRequestCache::ClientCompositionRequest::ClientCompositionRequest(
+ const renderengine::DisplaySettings& initDisplay,
+ const std::vector<LayerFE::LayerSettings>& initLayerSettings)
+ : display(initDisplay) {
+ layerSettings.reserve(initLayerSettings.size());
+ for (const LayerFE::LayerSettings& settings : initLayerSettings) {
+ layerSettings.push_back(getLayerSettingsSnapshot(settings));
+ }
+}
+
+bool ClientCompositionRequestCache::ClientCompositionRequest::equals(
+ const renderengine::DisplaySettings& newDisplay,
+ const std::vector<LayerFE::LayerSettings>& newLayerSettings) const {
+ return newDisplay == display &&
+ std::equal(layerSettings.begin(), layerSettings.end(), newLayerSettings.begin(),
+ newLayerSettings.end(), layerSettingsAreEqual);
+}
+
+bool ClientCompositionRequestCache::exists(
+ uint64_t bufferId, const renderengine::DisplaySettings& display,
+ const std::vector<LayerFE::LayerSettings>& layerSettings) const {
+ for (const auto& [cachedBufferId, cachedRequest] : mCache) {
+ if (cachedBufferId == bufferId) {
+ return cachedRequest.equals(display, layerSettings);
+ }
+ }
+ return false;
+}
+
+void ClientCompositionRequestCache::add(uint64_t bufferId,
+ const renderengine::DisplaySettings& display,
+ const std::vector<LayerFE::LayerSettings>& layerSettings) {
+ const ClientCompositionRequest request(display, layerSettings);
+ for (auto& [cachedBufferId, cachedRequest] : mCache) {
+ if (cachedBufferId == bufferId) {
+ cachedRequest = std::move(request);
+ return;
+ }
+ }
+
+ if (mCache.size() >= mMaxCacheSize) {
+ mCache.pop_front();
+ }
+
+ mCache.emplace_back(bufferId, std::move(request));
+}
+
+void ClientCompositionRequestCache::remove(uint64_t bufferId) {
+ for (auto it = mCache.begin(); it != mCache.end(); it++) {
+ if (it->first == bufferId) {
+ mCache.erase(it);
+ return;
+ }
+ }
+}
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 20f765c..13f5137 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -137,6 +137,10 @@
compositionengine::impl::createRenderSurface(getCompositionEngine(), *this, args));
}
+void Display::createClientCompositionCache(uint32_t cacheSize) {
+ cacheClientCompositionRequests(cacheSize);
+}
+
std::unique_ptr<compositionengine::OutputLayer> Display::createOutputLayer(
const std::shared_ptr<compositionengine::Layer>& layer,
const sp<compositionengine::LayerFE>& layerFE) const {
diff --git a/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
index 995a0ca..1e7c97c 100644
--- a/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
@@ -35,7 +35,7 @@
slot >= BufferQueue::NUM_BUFFER_SLOTS) {
*outSlot = 0;
} else {
- *outSlot = slot;
+ *outSlot = static_cast<uint32_t>(slot);
}
auto& currentBuffer = mBuffers[*outSlot];
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 650b5c1..61dadfd 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -101,7 +101,7 @@
dirtyEntireOutput();
}
-void Output::setProjection(const ui::Transform& transform, int32_t orientation, const Rect& frame,
+void Output::setProjection(const ui::Transform& transform, uint32_t orientation, const Rect& frame,
const Rect& viewport, const Rect& scissor, bool needsFiltering) {
auto& outputState = editState();
outputState.transform = transform;
@@ -231,6 +231,14 @@
dirtyEntireOutput();
}
+void Output::cacheClientCompositionRequests(uint32_t cacheSize) {
+ if (cacheSize == 0) {
+ mClientCompositionRequestCache.reset();
+ } else {
+ mClientCompositionRequestCache = std::make_unique<ClientCompositionRequestCache>(cacheSize);
+ }
+};
+
void Output::setRenderSurfaceForTest(std::unique_ptr<compositionengine::RenderSurface> surface) {
mRenderSurface = std::move(surface);
}
@@ -433,7 +441,7 @@
if (layerFEState.shadowRadius > 0.0f) {
// if the layer casts a shadow, offset the layers visible region and
// calculate the shadow region.
- const int32_t inset = layerFEState.shadowRadius * -1.0f;
+ const auto inset = static_cast<int32_t>(ceilf(layerFEState.shadowRadius) * -1.0f);
Rect visibleRectWithShadows(visibleRect);
visibleRectWithShadows.inset(inset, inset, inset, inset);
visibleRegion.set(visibleRectWithShadows);
@@ -457,7 +465,7 @@
}
// compute the opaque region
- const int32_t layerOrientation = tr.getOrientation();
+ const auto layerOrientation = tr.getOrientation();
if (layerFEState.isOpaque && ((layerOrientation & ui::Transform::ROT_INVALID) == 0)) {
// If we one of the simple category of transforms (0/90/180/270 rotation
// + any flip), then the opaque region is the layer's footprint.
@@ -806,6 +814,7 @@
ALOGV(__FUNCTION__);
const auto& outputState = getState();
+ OutputCompositionState& outputCompositionState = editState();
const TracedOrdinal<bool> hasClientComposition = {"hasClientComposition",
outputState.usesClientComposition};
base::unique_fd readyFence;
@@ -839,7 +848,7 @@
clientCompositionDisplay.clearRegion = Region::INVALID_REGION;
// Generate the client composition requests for the layers on this output.
- std::vector<renderengine::LayerSettings> clientCompositionLayers =
+ std::vector<LayerFE::LayerSettings> clientCompositionLayers =
generateClientCompositionRequests(supportsProtectedContent,
clientCompositionDisplay.clearRegion,
clientCompositionDisplay.outputDataspace);
@@ -871,6 +880,19 @@
return std::nullopt;
}
+ // Check if the client composition requests were rendered into the provided graphic buffer. If
+ // so, we can reuse the buffer and avoid client composition.
+ if (mClientCompositionRequestCache) {
+ if (mClientCompositionRequestCache->exists(buf->getId(), clientCompositionDisplay,
+ clientCompositionLayers)) {
+ outputCompositionState.reusedClientComposition = true;
+ setExpensiveRenderingExpected(false);
+ return readyFence;
+ }
+ mClientCompositionRequestCache->add(buf->getId(), clientCompositionDisplay,
+ clientCompositionLayers);
+ }
+
// We boost GPU frequency here because there will be color spaces conversion
// or complex GPU shaders and it's expensive. We boost the GPU frequency so that
// GPU composition can finish in time. We must reset GPU frequency afterwards,
@@ -882,10 +904,25 @@
setExpensiveRenderingExpected(true);
}
+ std::vector<const renderengine::LayerSettings*> clientCompositionLayerPointers;
+ clientCompositionLayerPointers.reserve(clientCompositionLayers.size());
+ std::transform(clientCompositionLayers.begin(), clientCompositionLayers.end(),
+ std::back_inserter(clientCompositionLayerPointers),
+ [](LayerFE::LayerSettings& settings) -> renderengine::LayerSettings* {
+ return &settings;
+ });
+
const nsecs_t renderEngineStart = systemTime();
- renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayers,
- buf->getNativeBuffer(), /*useFramebufferCache=*/true, std::move(fd),
- &readyFence);
+ status_t status =
+ renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayerPointers,
+ buf->getNativeBuffer(), /*useFramebufferCache=*/true,
+ std::move(fd), &readyFence);
+
+ if (status != NO_ERROR && mClientCompositionRequestCache) {
+ // If rendering was not successful, remove the request from the cache.
+ mClientCompositionRequestCache->remove(buf->getId());
+ }
+
auto& timeStats = getCompositionEngine().getTimeStats();
if (readyFence.get() < 0) {
timeStats.recordRenderEngineDuration(renderEngineStart, systemTime());
@@ -898,9 +935,9 @@
return readyFence;
}
-std::vector<renderengine::LayerSettings> Output::generateClientCompositionRequests(
+std::vector<LayerFE::LayerSettings> Output::generateClientCompositionRequests(
bool supportsProtectedContent, Region& clearRegion, ui::Dataspace outputDataspace) {
- std::vector<renderengine::LayerSettings> clientCompositionLayers;
+ std::vector<LayerFE::LayerSettings> clientCompositionLayers;
ALOGV("Rendering client layers");
const auto& outputState = getState();
@@ -944,15 +981,17 @@
supportsProtectedContent,
clientComposition ? clearRegion : dummyRegion,
};
- if (auto result = layerFE.prepareClientComposition(targetSettings)) {
+ if (std::optional<LayerFE::LayerSettings> result =
+ layerFE.prepareClientComposition(targetSettings)) {
if (!clientComposition) {
- auto& layerSettings = *result;
+ LayerFE::LayerSettings& layerSettings = *result;
layerSettings.source.buffer.buffer = nullptr;
layerSettings.source.solidColor = half3(0.0, 0.0, 0.0);
layerSettings.alpha = half(0.0);
layerSettings.disableBlending = true;
+ layerSettings.frameNumber = 0;
} else {
- std::optional<renderengine::LayerSettings> shadowLayer =
+ std::optional<LayerFE::LayerSettings> shadowLayer =
layerFE.prepareShadowClientComposition(*result, outputState.viewport,
outputDataspace);
if (shadowLayer) {
@@ -979,13 +1018,12 @@
}
void Output::appendRegionFlashRequests(
- const Region& flashRegion,
- std::vector<renderengine::LayerSettings>& clientCompositionLayers) {
+ const Region& flashRegion, std::vector<LayerFE::LayerSettings>& clientCompositionLayers) {
if (flashRegion.isEmpty()) {
return;
}
- renderengine::LayerSettings layerSettings;
+ LayerFE::LayerSettings layerSettings;
layerSettings.source.buffer.buffer = nullptr;
layerSettings.source.solidColor = half3(1.0, 0.0, 1.0);
layerSettings.alpha = half(1.0);
@@ -1065,6 +1103,7 @@
auto& outputState = editState();
outputState.usesClientComposition = true;
outputState.usesDeviceComposition = false;
+ outputState.reusedClientComposition = false;
}
bool Output::getSkipColorTransform() const {
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
index 0fcc308..84d79f7 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
@@ -27,6 +27,7 @@
dumpVal(out, "usesClientComposition", usesClientComposition);
dumpVal(out, "usesDeviceComposition", usesDeviceComposition);
dumpVal(out, "flipClientTarget", flipClientTarget);
+ dumpVal(out, "reusedClientComposition", reusedClientComposition);
dumpVal(out, "layerStack", layerStackId);
dumpVal(out, "layerStackInternal", layerStackInternal);
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index ac66d8c..914a047 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -392,7 +392,8 @@
outputIndependentState.alpha, to_string(error).c_str(), static_cast<int32_t>(error));
}
- if (auto error = hwcLayer->setInfo(outputIndependentState.type, outputIndependentState.appId);
+ if (auto error = hwcLayer->setInfo(static_cast<uint32_t>(outputIndependentState.type),
+ static_cast<uint32_t>(outputIndependentState.appId));
error != HWC2::Error::None) {
ALOGE("[%s] Failed to set info %s (%d)", getLayerFE().getDebugName(),
to_string(error).c_str(), static_cast<int32_t>(error));
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index 10512eb..e981172 100644
--- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -91,7 +91,8 @@
}
void RenderSurface::setDisplaySize(const ui::Size& size) {
- mDisplaySurface->resizeBuffers(size.width, size.height);
+ mDisplaySurface->resizeBuffers(static_cast<uint32_t>(size.width),
+ static_cast<uint32_t>(size.height));
mSize = size;
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
index ebcd0a0..bcaa529 100644
--- a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
@@ -139,14 +139,14 @@
struct CompositionEngineUpdateCursorAsyncTest : public CompositionEngineTest {
public:
CompositionEngineUpdateCursorAsyncTest() {
- EXPECT_CALL(*mOutput1, getOutputLayerCount()).WillRepeatedly(Return(0));
+ EXPECT_CALL(*mOutput1, getOutputLayerCount()).WillRepeatedly(Return(0u));
EXPECT_CALL(*mOutput1, getOutputLayerOrderedByZByIndex(_)).Times(0);
- EXPECT_CALL(*mOutput2, getOutputLayerCount()).WillRepeatedly(Return(1));
+ EXPECT_CALL(*mOutput2, getOutputLayerCount()).WillRepeatedly(Return(1u));
EXPECT_CALL(*mOutput2, getOutputLayerOrderedByZByIndex(0))
.WillRepeatedly(Return(&mOutput2OutputLayer1));
- EXPECT_CALL(*mOutput3, getOutputLayerCount()).WillRepeatedly(Return(2));
+ EXPECT_CALL(*mOutput3, getOutputLayerCount()).WillRepeatedly(Return(2u));
EXPECT_CALL(*mOutput3, getOutputLayerOrderedByZByIndex(0))
.WillRepeatedly(Return(&mOutput3OutputLayer1));
EXPECT_CALL(*mOutput3, getOutputLayerOrderedByZByIndex(1))
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 6761b86..9a2889e 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -47,12 +47,14 @@
using testing::ByMove;
using testing::ByRef;
using testing::DoAll;
+using testing::ElementsAre;
using testing::ElementsAreArray;
using testing::Eq;
using testing::InSequence;
using testing::Invoke;
using testing::IsEmpty;
using testing::Mock;
+using testing::Pointee;
using testing::Property;
using testing::Ref;
using testing::Return;
@@ -62,10 +64,11 @@
constexpr auto TR_IDENT = 0u;
constexpr auto TR_ROT_90 = HAL_TRANSFORM_ROT_90;
+constexpr auto MAX_CLIENT_COMPOSITION_CACHE_SIZE = 3;
const mat4 kIdentity;
-const mat4 kNonIdentityHalf = mat4() * 0.5;
-const mat4 kNonIdentityQuarter = mat4() * 0.25;
+const mat4 kNonIdentityHalf = mat4() * 0.5f;
+const mat4 kNonIdentityQuarter = mat4() * 0.25f;
constexpr OutputColorSetting kVendorSpecifiedOutputColorSetting =
static_cast<OutputColorSetting>(0x100);
@@ -988,7 +991,7 @@
};
OutputCollectVisibleLayersTest() {
- EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(3));
+ EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(3u));
EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(0))
.WillRepeatedly(Return(&mLayer1.outputLayer));
EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(1))
@@ -1012,7 +1015,7 @@
TEST_F(OutputCollectVisibleLayersTest, doesMinimalWorkIfNoLayers) {
mRefreshArgs.layers.clear();
- EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0));
+ EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u));
EXPECT_CALL(mOutput, setReleasedLayers(Ref(mRefreshArgs)));
EXPECT_CALL(mOutput, finalizePendingOutputLayers());
@@ -1062,7 +1065,7 @@
EXPECT_CALL(*mLayer, editFEState()).WillRepeatedly(ReturnRef(mLayerFEState));
EXPECT_CALL(mOutput, belongsInOutput(mLayer.get())).WillRepeatedly(Return(true));
- EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(1));
+ EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(1u));
EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(0u))
.WillRepeatedly(Return(&mOutputLayer));
@@ -1627,7 +1630,7 @@
// When the outputColorSetting is set to kUnmanaged, the implementation sets
// a simple default color profile without looking at anything else.
- EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(3));
+ EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(3u));
EXPECT_CALL(mOutput,
setColorProfile(ColorProfileEq(
ColorProfile{ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN,
@@ -1642,7 +1645,7 @@
struct OutputUpdateColorProfileTest_GetBestColorModeResultBecomesSetProfile
: public OutputUpdateColorProfileTest {
OutputUpdateColorProfileTest_GetBestColorModeResultBecomesSetProfile() {
- EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0));
+ EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u));
mRefreshArgs.outputColorSetting = OutputColorSetting::kEnhanced;
mRefreshArgs.colorSpaceAgnosticDataspace = ui::Dataspace::UNKNOWN;
}
@@ -1690,7 +1693,7 @@
struct OutputUpdateColorProfileTest_ColorSpaceAgnosticeDataspaceAffectsSetColorProfile
: public OutputUpdateColorProfileTest {
OutputUpdateColorProfileTest_ColorSpaceAgnosticeDataspaceAffectsSetColorProfile() {
- EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0));
+ EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u));
EXPECT_CALL(*mDisplayColorProfile,
getBestColorMode(ui::Dataspace::V0_SRGB, ui::RenderIntent::ENHANCE, _, _, _))
.WillRepeatedly(DoAll(SetArgPointee<2>(ui::Dataspace::UNKNOWN),
@@ -1746,7 +1749,7 @@
mRefreshArgs.outputColorSetting = OutputColorSetting::kEnhanced;
mRefreshArgs.colorSpaceAgnosticDataspace = ui::Dataspace::UNKNOWN;
- EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(3));
+ EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(3u));
EXPECT_CALL(mOutput, setColorProfile(_)).WillRepeatedly(Return());
}
@@ -1868,7 +1871,7 @@
mLayer1.mLayerFEState.dataspace = ui::Dataspace::DISPLAY_BT2020;
- EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(1));
+ EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(1u));
EXPECT_CALL(mOutput, setColorProfile(_)).WillRepeatedly(Return());
}
@@ -1921,7 +1924,7 @@
OutputUpdateColorProfileTest_Hdr() {
mRefreshArgs.outputColorSetting = OutputColorSetting::kEnhanced;
mRefreshArgs.colorSpaceAgnosticDataspace = ui::Dataspace::UNKNOWN;
- EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(2));
+ EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(2u));
EXPECT_CALL(mOutput, setColorProfile(_)).WillRepeatedly(Return());
}
@@ -2201,7 +2204,7 @@
mRefreshArgs.outputColorSetting = OutputColorSetting::kEnhanced;
mRefreshArgs.colorSpaceAgnosticDataspace = ui::Dataspace::UNKNOWN;
mLayer1.mLayerFEState.dataspace = ui::Dataspace::BT2020_PQ;
- EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(1));
+ EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(1u));
EXPECT_CALL(mOutput, setColorProfile(_)).WillRepeatedly(Return());
EXPECT_CALL(*mDisplayColorProfile, hasLegacyHdrSupport(ui::Dataspace::BT2020_PQ))
.WillRepeatedly(Return(false));
@@ -2765,9 +2768,9 @@
// mock implementations.
MOCK_CONST_METHOD0(getSkipColorTransform, bool());
MOCK_METHOD3(generateClientCompositionRequests,
- std::vector<renderengine::LayerSettings>(bool, Region&, ui::Dataspace));
+ std::vector<LayerFE::LayerSettings>(bool, Region&, ui::Dataspace));
MOCK_METHOD2(appendRegionFlashRequests,
- void(const Region&, std::vector<renderengine::LayerSettings>&));
+ void(const Region&, std::vector<LayerFE::LayerSettings>&));
MOCK_METHOD1(setExpensiveRenderingExpected, void(bool));
};
@@ -2775,6 +2778,7 @@
mOutput.setDisplayColorProfileForTest(
std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile));
mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
+ mOutput.cacheClientCompositionRequests(MAX_CLIENT_COMPOSITION_CACHE_SIZE);
mOutput.mState.frame = kDefaultOutputFrame;
mOutput.mState.viewport = kDefaultOutputViewport;
@@ -2787,6 +2791,7 @@
mOutput.mState.needsFiltering = false;
mOutput.mState.usesClientComposition = true;
mOutput.mState.usesDeviceComposition = false;
+ mOutput.mState.reusedClientComposition = false;
EXPECT_CALL(mOutput, getCompositionEngine()).WillRepeatedly(ReturnRef(mCompositionEngine));
EXPECT_CALL(mCompositionEngine, getRenderEngine()).WillRepeatedly(ReturnRef(mRenderEngine));
@@ -2842,7 +2847,7 @@
const Rect OutputComposeSurfacesTest::kDefaultOutputFrame{1001, 1002, 1003, 1004};
const Rect OutputComposeSurfacesTest::kDefaultOutputViewport{1005, 1006, 1007, 1008};
const Rect OutputComposeSurfacesTest::kDefaultOutputScissor{1009, 1010, 1011, 1012};
-const mat4 OutputComposeSurfacesTest::kDefaultColorTransformMat{mat4() * 0.5};
+const mat4 OutputComposeSurfacesTest::kDefaultColorTransformMat{mat4() * 0.5f};
const Region OutputComposeSurfacesTest::kDebugRegion{Rect{100, 101, 102, 103}};
const HdrCapabilities OutputComposeSurfacesTest::
kHdrCapabilities{{},
@@ -2863,7 +2868,7 @@
EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
- .WillRepeatedly(Return(std::vector<renderengine::LayerSettings>{}));
+ .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{}));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
.WillRepeatedly(Return());
@@ -2877,7 +2882,7 @@
EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
- .WillRepeatedly(Return(std::vector<renderengine::LayerSettings>{}));
+ .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{}));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
.WillRepeatedly(Return());
@@ -2889,8 +2894,8 @@
}
TEST_F(OutputComposeSurfacesTest, buildsAndRendersRequestList) {
- renderengine::LayerSettings r1;
- renderengine::LayerSettings r2;
+ LayerFE::LayerSettings r1;
+ LayerFE::LayerSettings r2;
r1.geometry.boundaries = FloatRect{1, 2, 3, 4};
r2.geometry.boundaries = FloatRect{5, 6, 7, 8};
@@ -2899,26 +2904,143 @@
EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
- .WillRepeatedly(Return(std::vector<renderengine::LayerSettings>{r1}));
+ .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1}));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
.WillRepeatedly(
Invoke([&](const Region&,
- std::vector<renderengine::LayerSettings>& clientCompositionLayers) {
+ std::vector<LayerFE::LayerSettings>& clientCompositionLayers) {
clientCompositionLayers.emplace_back(r2);
}));
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
- EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAreArray({r1, r2}), _, true, _, _))
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, true, _, _))
.WillRepeatedly(Return(NO_ERROR));
verify().execute().expectAFenceWasReturned();
}
+TEST_F(OutputComposeSurfacesTest, renderDuplicateClientCompositionRequestsWithoutCache) {
+ mOutput.cacheClientCompositionRequests(0);
+ LayerFE::LayerSettings r1;
+ LayerFE::LayerSettings r2;
+
+ r1.geometry.boundaries = FloatRect{1, 2, 3, 4};
+ r2.geometry.boundaries = FloatRect{5, 6, 7, 8};
+
+ EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
+ EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
+ EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
+ .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1, r2}));
+ EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
+ .WillRepeatedly(Return());
+
+ EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, true, _, _))
+ .Times(2)
+ .WillOnce(Return(NO_ERROR));
+
+ verify().execute().expectAFenceWasReturned();
+ EXPECT_FALSE(mOutput.mState.reusedClientComposition);
+
+ verify().execute().expectAFenceWasReturned();
+ EXPECT_FALSE(mOutput.mState.reusedClientComposition);
+}
+
+TEST_F(OutputComposeSurfacesTest, skipDuplicateClientCompositionRequests) {
+ mOutput.cacheClientCompositionRequests(3);
+ LayerFE::LayerSettings r1;
+ LayerFE::LayerSettings r2;
+
+ r1.geometry.boundaries = FloatRect{1, 2, 3, 4};
+ r2.geometry.boundaries = FloatRect{5, 6, 7, 8};
+
+ EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
+ EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
+ EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
+ .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1, r2}));
+ EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
+ .WillRepeatedly(Return());
+
+ EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, true, _, _))
+ .WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mOutput, setExpensiveRenderingExpected(false));
+
+ verify().execute().expectAFenceWasReturned();
+ EXPECT_FALSE(mOutput.mState.reusedClientComposition);
+
+ // We do not expect another call to draw layers.
+ verify().execute().expectAFenceWasReturned();
+ EXPECT_TRUE(mOutput.mState.reusedClientComposition);
+}
+
+TEST_F(OutputComposeSurfacesTest, clientCompositionIfBufferChanges) {
+ LayerFE::LayerSettings r1;
+ LayerFE::LayerSettings r2;
+
+ r1.geometry.boundaries = FloatRect{1, 2, 3, 4};
+ r2.geometry.boundaries = FloatRect{5, 6, 7, 8};
+
+ EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
+ EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
+ EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
+ .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1, r2}));
+ EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
+ .WillRepeatedly(Return());
+
+ sp<GraphicBuffer> otherOutputBuffer = new GraphicBuffer();
+ EXPECT_CALL(*mRenderSurface, dequeueBuffer(_))
+ .WillOnce(Return(mOutputBuffer))
+ .WillOnce(Return(otherOutputBuffer));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, true, _, _))
+ .WillRepeatedly(Return(NO_ERROR));
+
+ verify().execute().expectAFenceWasReturned();
+ EXPECT_FALSE(mOutput.mState.reusedClientComposition);
+
+ verify().execute().expectAFenceWasReturned();
+ EXPECT_FALSE(mOutput.mState.reusedClientComposition);
+}
+
+TEST_F(OutputComposeSurfacesTest, clientCompositionIfRequestChanges) {
+ LayerFE::LayerSettings r1;
+ LayerFE::LayerSettings r2;
+ LayerFE::LayerSettings r3;
+
+ r1.geometry.boundaries = FloatRect{1, 2, 3, 4};
+ r2.geometry.boundaries = FloatRect{5, 6, 7, 8};
+ r3.geometry.boundaries = FloatRect{5, 6, 7, 9};
+
+ EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
+ EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
+ EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>{r1, r2}))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>{r1, r3}));
+ EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
+ .WillRepeatedly(Return());
+
+ EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, true, _, _))
+ .WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r3)), _, true, _, _))
+ .WillOnce(Return(NO_ERROR));
+
+ verify().execute().expectAFenceWasReturned();
+ EXPECT_FALSE(mOutput.mState.reusedClientComposition);
+
+ verify().execute().expectAFenceWasReturned();
+ EXPECT_FALSE(mOutput.mState.reusedClientComposition);
+}
+
struct OutputComposeSurfacesTest_UsesExpectedDisplaySettings : public OutputComposeSurfacesTest {
OutputComposeSurfacesTest_UsesExpectedDisplaySettings() {
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
- .WillRepeatedly(Return(std::vector<renderengine::LayerSettings>{}));
+ .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{}));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
.WillRepeatedly(Return());
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
@@ -3048,7 +3170,7 @@
EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, _))
- .WillRepeatedly(Return(std::vector<renderengine::LayerSettings>{}));
+ .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{}));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
.WillRepeatedly(Return());
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
@@ -3166,7 +3288,7 @@
mOutput.mState.dataspace = kExpensiveOutputDataspace;
EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kExpensiveOutputDataspace))
- .WillOnce(Return(std::vector<renderengine::LayerSettings>{}));
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>{}));
// For this test, we also check the call order of key functions.
InSequence seq;
@@ -3184,7 +3306,7 @@
struct GenerateClientCompositionRequestsTest : public testing::Test {
struct OutputPartialMock : public OutputPartialMockBase {
// compositionengine::Output overrides
- std::vector<renderengine::LayerSettings> generateClientCompositionRequests(
+ std::vector<LayerFE::LayerSettings> generateClientCompositionRequests(
bool supportsProtectedContent, Region& clearRegion,
ui::Dataspace dataspace) override {
return impl::Output::generateClientCompositionRequests(supportsProtectedContent,
@@ -3206,7 +3328,7 @@
StrictMock<mock::LayerFE> mLayerFE;
LayerFECompositionState mLayerFEState;
impl::OutputLayerCompositionState mOutputLayerState;
- renderengine::LayerSettings mRELayerSettings;
+ LayerFE::LayerSettings mLayerSettings;
};
GenerateClientCompositionRequestsTest() {
@@ -3237,11 +3359,11 @@
mLayers[i].mOutputLayerState.clearClientTarget = false;
mLayers[i].mOutputLayerState.visibleRegion = Region(kDisplayFrame);
mLayers[i].mLayerFEState.isOpaque = true;
- mLayers[i].mRELayerSettings.geometry.boundaries =
+ mLayers[i].mLayerSettings.geometry.boundaries =
FloatRect{static_cast<float>(i + 1), 0.f, 0.f, 0.f};
- mLayers[i].mRELayerSettings.source.solidColor = {1.0f, 1.0f, 1.0f};
- mLayers[i].mRELayerSettings.alpha = 1.0f;
- mLayers[i].mRELayerSettings.disableBlending = false;
+ mLayers[i].mLayerSettings.source.solidColor = {1.0f, 1.0f, 1.0f};
+ mLayers[i].mLayerSettings.alpha = 1.0f;
+ mLayers[i].mLayerSettings.disableBlending = false;
EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(i))
.WillRepeatedly(Return(&mLayers[i].mOutputLayer));
@@ -3292,30 +3414,30 @@
}
TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, gathersClientCompositionRequests) {
- renderengine::LayerSettings mREShadowSettings;
- mREShadowSettings.source.solidColor = {0.1f, 0.1f, 0.1f};
+ LayerFE::LayerSettings mShadowSettings;
+ mShadowSettings.source.solidColor = {0.1f, 0.1f, 0.1f};
EXPECT_CALL(mLayers[0].mLayerFE, prepareClientComposition(_)).WillOnce(Return(std::nullopt));
EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(_))
- .WillOnce(Return(mLayers[1].mRELayerSettings));
+ .WillOnce(Return(mLayers[1].mLayerSettings));
EXPECT_CALL(mLayers[1].mLayerFE,
- prepareShadowClientComposition(mLayers[1].mRELayerSettings, kDisplayViewport,
+ prepareShadowClientComposition(mLayers[1].mLayerSettings, kDisplayViewport,
kDisplayDataspace))
.WillOnce(Return(std::nullopt));
EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_))
- .WillOnce(Return(mLayers[2].mRELayerSettings));
+ .WillOnce(Return(mLayers[2].mLayerSettings));
EXPECT_CALL(mLayers[2].mLayerFE,
- prepareShadowClientComposition(mLayers[2].mRELayerSettings, kDisplayViewport,
+ prepareShadowClientComposition(mLayers[2].mLayerSettings, kDisplayViewport,
kDisplayDataspace))
- .WillOnce(Return(mREShadowSettings));
+ .WillOnce(Return(mShadowSettings));
Region accumClearRegion(Rect(10, 11, 12, 13));
auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
accumClearRegion, kDisplayDataspace);
ASSERT_EQ(3u, requests.size());
- EXPECT_EQ(mLayers[1].mRELayerSettings, requests[0]);
- EXPECT_EQ(mREShadowSettings, requests[1]);
- EXPECT_EQ(mLayers[2].mRELayerSettings, requests[2]);
+ EXPECT_EQ(mLayers[1].mLayerSettings, requests[0]);
+ EXPECT_EQ(mShadowSettings, requests[1]);
+ EXPECT_EQ(mLayers[2].mLayerSettings, requests[2]);
EXPECT_THAT(accumClearRegion, RegionEq(Region(Rect(10, 11, 12, 13))));
@@ -3340,7 +3462,7 @@
mLayers[2].mLayerFEState.isOpaque = true;
EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_))
- .WillOnce(Return(mLayers[2].mRELayerSettings));
+ .WillOnce(Return(mLayers[2].mLayerSettings));
EXPECT_CALL(mLayers[2].mLayerFE, prepareShadowClientComposition(_, _, _))
.WillOnce(Return(std::nullopt));
@@ -3348,7 +3470,7 @@
auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
accumClearRegion, kDisplayDataspace);
ASSERT_EQ(1u, requests.size());
- EXPECT_EQ(mLayers[2].mRELayerSettings, requests[0]);
+ EXPECT_EQ(mLayers[2].mLayerSettings, requests[0]);
EXPECT_THAT(accumClearRegion, RegionEq(Region(Rect(10, 11, 12, 13))));
}
@@ -3368,7 +3490,7 @@
mLayers[2].mLayerFEState.isOpaque = false;
EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_))
- .WillOnce(Return(mLayers[2].mRELayerSettings));
+ .WillOnce(Return(mLayers[2].mLayerSettings));
EXPECT_CALL(mLayers[2].mLayerFE, prepareShadowClientComposition(_, _, _))
.WillOnce(Return(std::nullopt));
@@ -3376,7 +3498,7 @@
auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
accumClearRegion, kDisplayDataspace);
ASSERT_EQ(1u, requests.size());
- EXPECT_EQ(mLayers[2].mRELayerSettings, requests[0]);
+ EXPECT_EQ(mLayers[2].mLayerSettings, requests[0]);
EXPECT_THAT(accumClearRegion, RegionEq(Region(Rect(10, 11, 12, 13))));
}
@@ -3401,9 +3523,9 @@
mLayers[2].mLayerFEState.isOpaque = true;
EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(_))
- .WillOnce(Return(mLayers[1].mRELayerSettings));
+ .WillOnce(Return(mLayers[1].mLayerSettings));
EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_))
- .WillOnce(Return(mLayers[2].mRELayerSettings));
+ .WillOnce(Return(mLayers[2].mLayerSettings));
EXPECT_CALL(mLayers[2].mLayerFE, prepareShadowClientComposition(_, _, _))
.WillOnce(Return(std::nullopt));
@@ -3413,13 +3535,13 @@
ASSERT_EQ(2u, requests.size());
// The second layer is expected to be rendered as alpha=0 black with no blending
- EXPECT_EQ(mLayers[1].mRELayerSettings.geometry.boundaries, requests[0].geometry.boundaries);
+ EXPECT_EQ(mLayers[1].mLayerSettings.geometry.boundaries, requests[0].geometry.boundaries);
EXPECT_FALSE(requests[0].source.buffer.buffer);
EXPECT_EQ((half3{0.f, 0.f, 0.f}), requests[0].source.solidColor);
- EXPECT_EQ(half{0.f}, requests[0].alpha);
+ EXPECT_EQ(0.f, static_cast<float>(requests[0].alpha));
EXPECT_EQ(true, requests[0].disableBlending);
- EXPECT_EQ(mLayers[2].mRELayerSettings, requests[1]);
+ EXPECT_EQ(mLayers[2].mLayerSettings, requests[1]);
EXPECT_THAT(accumClearRegion, RegionEq(Region(Rect(10, 11, 12, 13))));
}
@@ -3689,12 +3811,12 @@
leftLayer.mOutputLayerState.clearClientTarget = false;
leftLayer.mOutputLayerState.visibleRegion = Region(Rect(0, 0, 1000, 1000));
leftLayer.mLayerFEState.isOpaque = true;
- leftLayer.mRELayerSettings.source.solidColor = {1.f, 0.f, 0.f};
+ leftLayer.mLayerSettings.source.solidColor = {1.f, 0.f, 0.f};
rightLayer.mOutputLayerState.clearClientTarget = false;
rightLayer.mOutputLayerState.visibleRegion = Region(Rect(1000, 0, 2000, 1000));
rightLayer.mLayerFEState.isOpaque = true;
- rightLayer.mRELayerSettings.source.solidColor = {0.f, 1.f, 0.f};
+ rightLayer.mLayerSettings.source.solidColor = {0.f, 1.f, 0.f};
EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(2u));
EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(0u))
@@ -3716,9 +3838,9 @@
EXPECT_CALL(leftLayer.mOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true));
EXPECT_CALL(leftLayer.mOutputLayer, needsFiltering()).WillRepeatedly(Return(false));
EXPECT_CALL(leftLayer.mLayerFE, prepareClientComposition(Eq(ByRef(leftLayerSettings))))
- .WillOnce(Return(leftLayer.mRELayerSettings));
+ .WillOnce(Return(leftLayer.mLayerSettings));
EXPECT_CALL(leftLayer.mLayerFE,
- prepareShadowClientComposition(leftLayer.mRELayerSettings, kPortraitViewport,
+ prepareShadowClientComposition(leftLayer.mLayerSettings, kPortraitViewport,
kOutputDataspace))
.WillOnce(Return(std::nullopt));
@@ -3734,9 +3856,9 @@
EXPECT_CALL(rightLayer.mOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true));
EXPECT_CALL(rightLayer.mOutputLayer, needsFiltering()).WillRepeatedly(Return(false));
EXPECT_CALL(rightLayer.mLayerFE, prepareClientComposition(Eq(ByRef(rightLayerSettings))))
- .WillOnce(Return(rightLayer.mRELayerSettings));
+ .WillOnce(Return(rightLayer.mLayerSettings));
EXPECT_CALL(rightLayer.mLayerFE,
- prepareShadowClientComposition(rightLayer.mRELayerSettings, kPortraitViewport,
+ prepareShadowClientComposition(rightLayer.mLayerSettings, kPortraitViewport,
kOutputDataspace))
.WillOnce(Return(std::nullopt));
@@ -3744,8 +3866,8 @@
auto requests = mOutput.generateClientCompositionRequests(supportsProtectedContent,
accumClearRegion, kOutputDataspace);
ASSERT_EQ(2u, requests.size());
- EXPECT_EQ(leftLayer.mRELayerSettings, requests[0]);
- EXPECT_EQ(rightLayer.mRELayerSettings, requests[1]);
+ EXPECT_EQ(leftLayer.mLayerSettings, requests[0]);
+ EXPECT_EQ(rightLayer.mLayerSettings, requests[1]);
}
TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers,
@@ -3755,8 +3877,8 @@
const Region kShadowRegion = Region(kContentWithShadow).subtract(kContent);
const Region kPartialShadowRegion = Region(kContentWithShadow).subtract(Rect(40, 40, 60, 80));
- renderengine::LayerSettings mREShadowSettings;
- mREShadowSettings.source.solidColor = {0.1f, 0.1f, 0.1f};
+ LayerFE::LayerSettings mShadowSettings;
+ mShadowSettings.source.solidColor = {0.1f, 0.1f, 0.1f};
mLayers[2].mOutputLayerState.visibleRegion = kPartialShadowRegion;
mLayers[2].mOutputLayerState.shadowRegion = kShadowRegion;
@@ -3764,18 +3886,18 @@
EXPECT_CALL(mLayers[0].mOutputLayer, requiresClientComposition()).WillOnce(Return(false));
EXPECT_CALL(mLayers[1].mOutputLayer, requiresClientComposition()).WillOnce(Return(false));
EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_))
- .WillOnce(Return(mLayers[2].mRELayerSettings));
+ .WillOnce(Return(mLayers[2].mLayerSettings));
EXPECT_CALL(mLayers[2].mLayerFE,
- prepareShadowClientComposition(mLayers[2].mRELayerSettings, kDisplayViewport,
+ prepareShadowClientComposition(mLayers[2].mLayerSettings, kDisplayViewport,
kDisplayDataspace))
- .WillOnce(Return(mREShadowSettings));
+ .WillOnce(Return(mShadowSettings));
Region accumClearRegion(Rect(10, 11, 12, 13));
auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
accumClearRegion, kDisplayDataspace);
ASSERT_EQ(1u, requests.size());
- EXPECT_EQ(mREShadowSettings, requests[0]);
+ EXPECT_EQ(mShadowSettings, requests[0]);
}
TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers,
@@ -3786,8 +3908,8 @@
const Region kPartialContentWithPartialShadowRegion =
Region(kContentWithShadow).subtract(Rect(40, 40, 50, 80));
- renderengine::LayerSettings mREShadowSettings;
- mREShadowSettings.source.solidColor = {0.1f, 0.1f, 0.1f};
+ LayerFE::LayerSettings mShadowSettings;
+ mShadowSettings.source.solidColor = {0.1f, 0.1f, 0.1f};
mLayers[2].mOutputLayerState.visibleRegion = kPartialContentWithPartialShadowRegion;
mLayers[2].mOutputLayerState.shadowRegion = kShadowRegion;
@@ -3795,19 +3917,19 @@
EXPECT_CALL(mLayers[0].mOutputLayer, requiresClientComposition()).WillOnce(Return(false));
EXPECT_CALL(mLayers[1].mOutputLayer, requiresClientComposition()).WillOnce(Return(false));
EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_))
- .WillOnce(Return(mLayers[2].mRELayerSettings));
+ .WillOnce(Return(mLayers[2].mLayerSettings));
EXPECT_CALL(mLayers[2].mLayerFE,
- prepareShadowClientComposition(mLayers[2].mRELayerSettings, kDisplayViewport,
+ prepareShadowClientComposition(mLayers[2].mLayerSettings, kDisplayViewport,
kDisplayDataspace))
- .WillOnce(Return(mREShadowSettings));
+ .WillOnce(Return(mShadowSettings));
Region accumClearRegion(Rect(10, 11, 12, 13));
auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
accumClearRegion, kDisplayDataspace);
ASSERT_EQ(2u, requests.size());
- EXPECT_EQ(mREShadowSettings, requests[0]);
- EXPECT_EQ(mLayers[2].mRELayerSettings, requests[1]);
+ EXPECT_EQ(mShadowSettings, requests[0]);
+ EXPECT_EQ(mLayers[2].mLayerSettings, requests[1]);
}
} // namespace
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index e2122d1..4ae6dad 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -70,6 +70,12 @@
args.nativeWindow.get()),
args.nativeWindow, args.displaySurface});
+ if (!mFlinger->mDisableClientCompositionCache &&
+ SurfaceFlinger::maxFrameBufferAcquiredBuffers > 0) {
+ mCompositionDisplay->createClientCompositionCache(
+ static_cast<uint32_t>(SurfaceFlinger::maxFrameBufferAcquiredBuffers));
+ }
+
mCompositionDisplay->createDisplayColorProfile(
compositionengine::DisplayColorProfileCreationArgs{args.hasWideColorGamut,
std::move(args.hdrCapabilities),
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index f4d4329..11ae46d 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -551,7 +551,7 @@
// drawing...
// ---------------------------------------------------------------------------
-std::optional<renderengine::LayerSettings> Layer::prepareClientComposition(
+std::optional<compositionengine::LayerFE::LayerSettings> Layer::prepareClientComposition(
compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
if (!getCompositionLayer()) {
return {};
@@ -559,7 +559,8 @@
FloatRect bounds = getBounds();
half alpha = getAlpha();
- renderengine::LayerSettings layerSettings;
+
+ compositionengine::LayerFE::LayerSettings layerSettings;
layerSettings.geometry.boundaries = bounds;
if (targetSettings.useIdentityTransform) {
layerSettings.geometry.positionTransform = mat4();
@@ -581,8 +582,8 @@
return layerSettings;
}
-std::optional<renderengine::LayerSettings> Layer::prepareShadowClientComposition(
- const renderengine::LayerSettings& casterLayerSettings, const Rect& displayViewport,
+std::optional<compositionengine::LayerFE::LayerSettings> Layer::prepareShadowClientComposition(
+ const LayerFE::LayerSettings& casterLayerSettings, const Rect& displayViewport,
ui::Dataspace outputDataspace) {
renderengine::ShadowSettings shadow = getShadowSettings(displayViewport);
if (shadow.length <= 0.f) {
@@ -593,7 +594,8 @@
const bool casterIsOpaque = ((casterLayerSettings.source.buffer.buffer != nullptr) &&
casterLayerSettings.source.buffer.isOpaque);
- renderengine::LayerSettings shadowLayer = casterLayerSettings;
+ compositionengine::LayerFE::LayerSettings shadowLayer = casterLayerSettings;
+
shadowLayer.shadow = shadow;
shadowLayer.geometry.boundaries = mBounds; // ignore transparent region
@@ -604,13 +606,16 @@
shadowLayer.shadow.spotColor *= casterAlpha;
shadowLayer.sourceDataspace = outputDataspace;
shadowLayer.source.buffer.buffer = nullptr;
+ shadowLayer.source.buffer.fence = nullptr;
+ shadowLayer.frameNumber = 0;
+ shadowLayer.bufferId = 0;
if (shadowLayer.shadow.ambientColor.a <= 0.f && shadowLayer.shadow.spotColor.a <= 0.f) {
return {};
}
float casterCornerRadius = shadowLayer.geometry.roundedCornersRadius;
- const FloatRect& cornerRadiusCropRect = casterLayerSettings.geometry.roundedCornersCrop;
+ const FloatRect& cornerRadiusCropRect = shadowLayer.geometry.roundedCornersCrop;
const FloatRect& casterRect = shadowLayer.geometry.boundaries;
// crop used to set the corner radius may be larger than the content rect. Adjust the corner
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index ffe004f..6acf5fb 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -527,10 +527,10 @@
void latchCompositionState(compositionengine::LayerFECompositionState&,
compositionengine::LayerFE::StateSubset subset) const override;
void latchCursorCompositionState(compositionengine::LayerFECompositionState&) const override;
- std::optional<renderengine::LayerSettings> prepareClientComposition(
+ std::optional<LayerSettings> prepareClientComposition(
compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
- std::optional<renderengine::LayerSettings> prepareShadowClientComposition(
- const renderengine::LayerSettings& layerSettings, const Rect& displayViewport,
+ std::optional<LayerSettings> prepareShadowClientComposition(
+ const LayerFE::LayerSettings& layerSettings, const Rect& displayViewport,
ui::Dataspace outputDataspace) override;
void onLayerDisplayed(const sp<Fence>& releaseFence) override;
const char* getDebugName() const override;
diff --git a/services/surfaceflinger/Scheduler/SchedulerUtils.h b/services/surfaceflinger/Scheduler/SchedulerUtils.h
index d301b99..e7e73a3 100644
--- a/services/surfaceflinger/Scheduler/SchedulerUtils.h
+++ b/services/surfaceflinger/Scheduler/SchedulerUtils.h
@@ -16,6 +16,7 @@
#pragma once
+#include <utils/Timers.h>
#include <cinttypes>
#include <numeric>
#include <unordered_map>
@@ -70,6 +71,13 @@
return static_cast<int>(std::max_element(counts.begin(), counts.end(), compareCounts)->first);
}
+template <class T, size_t N>
+constexpr size_t arrayLen(T (&)[N]) {
+ return N;
+}
+
+static constexpr size_t max64print = std::numeric_limits<nsecs_t>::digits10 + 1;
+
} // namespace android::scheduler
namespace std {
diff --git a/services/surfaceflinger/Scheduler/Timer.cpp b/services/surfaceflinger/Scheduler/Timer.cpp
index fb4f315..8f81c2c 100644
--- a/services/surfaceflinger/Scheduler/Timer.cpp
+++ b/services/surfaceflinger/Scheduler/Timer.cpp
@@ -25,6 +25,7 @@
#include <chrono>
#include <cstdint>
+#include "SchedulerUtils.h"
#include "Timer.h"
namespace android::scheduler {
@@ -32,11 +33,6 @@
static constexpr size_t kReadPipe = 0;
static constexpr size_t kWritePipe = 1;
-template <class T, size_t N>
-constexpr size_t arrayLen(T (&)[N]) {
- return N;
-}
-
Timer::Timer()
: mTimerFd(timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK)),
mEpollFd(epoll_create1(EPOLL_CLOEXEC)) {
@@ -66,11 +62,8 @@
return systemTime(SYSTEM_TIME_MONOTONIC);
}
-constexpr char const* timerTraceTag = "AlarmInNs";
void Timer::alarmIn(std::function<void()> const& cb, nsecs_t fireIn) {
std::lock_guard<decltype(mMutex)> lk(mMutex);
- ATRACE_INT64(timerTraceTag, fireIn);
-
using namespace std::literals;
static constexpr int ns_per_s =
std::chrono::duration_cast<std::chrono::nanoseconds>(1s).count();
@@ -91,7 +84,6 @@
void Timer::alarmCancel() {
std::lock_guard<decltype(mMutex)> lk(mMutex);
- ATRACE_INT64(timerTraceTag, 0);
struct itimerspec old_timer;
struct itimerspec new_timer {
@@ -137,7 +129,6 @@
uint64_t iteration = 0;
char const traceNamePrefix[] = "TimerIteration #";
- static constexpr size_t max64print = std::numeric_limits<decltype(iteration)>::digits10;
static constexpr size_t maxlen = arrayLen(traceNamePrefix) + max64print;
std::array<char, maxlen> str_buffer;
auto timing = true;
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
index 2e5b6e9..d0f18ab 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
@@ -52,6 +52,13 @@
return {mArmedInfo->mActualWakeupTime};
}
+std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::targetVsync() const {
+ if (!mArmedInfo) {
+ return {};
+ }
+ return {mArmedInfo->mActualVsyncTime};
+}
+
ScheduleResult VSyncDispatchTimerQueueEntry::schedule(nsecs_t workDuration, nsecs_t earliestVsync,
VSyncTracker& tracker, nsecs_t now) {
auto nextVsyncTime =
@@ -143,9 +150,21 @@
rearmTimerSkippingUpdateFor(now, mCallbacks.end());
}
+void VSyncDispatchTimerQueue::TraceBuffer::note(std::string_view name, nsecs_t alarmIn,
+ nsecs_t vsFor) {
+ if (ATRACE_ENABLED()) {
+ snprintf(str_buffer.data(), str_buffer.size(), "%.4s%s%" PRId64 "%s%" PRId64,
+ name.substr(0, kMaxNamePrint).data(), kTraceNamePrefix, alarmIn,
+ kTraceNameSeparator, vsFor);
+ }
+ ATRACE_NAME(str_buffer.data());
+}
+
void VSyncDispatchTimerQueue::rearmTimerSkippingUpdateFor(
nsecs_t now, CallbackMap::iterator const& skipUpdateIt) {
std::optional<nsecs_t> min;
+ std::optional<nsecs_t> targetVsync;
+ std::optional<std::string_view> nextWakeupName;
for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
auto& callback = it->second;
if (!callback->wakeupTime()) {
@@ -157,13 +176,19 @@
}
auto const wakeupTime = *callback->wakeupTime();
if (!min || (min && *min > wakeupTime)) {
+ nextWakeupName = callback->name();
min = wakeupTime;
+ targetVsync = callback->targetVsync();
}
}
if (min && (min < mIntendedWakeupTime)) {
+ if (targetVsync && nextWakeupName) {
+ mTraceBuffer.note(*nextWakeupName, *min - now, *targetVsync - now);
+ }
setTimer(*min, now);
} else {
+ ATRACE_NAME("cancel timer");
cancelTimer();
}
}
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
index 087acc7..fd0a034 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
@@ -17,6 +17,7 @@
#pragma once
#include <android-base/thread_annotations.h>
+#include <array>
#include <functional>
#include <memory>
#include <mutex>
@@ -24,6 +25,7 @@
#include <string_view>
#include <unordered_map>
+#include "SchedulerUtils.h"
#include "VSyncDispatch.h"
namespace android::scheduler {
@@ -54,6 +56,8 @@
// It will not update the wakeupTime.
std::optional<nsecs_t> wakeupTime() const;
+ std::optional<nsecs_t> targetVsync() const;
+
// This moves state from armed->disarmed.
void disarm();
@@ -134,6 +138,17 @@
CallbackMap mCallbacks GUARDED_BY(mMutex);
nsecs_t mIntendedWakeupTime GUARDED_BY(mMutex) = kInvalidTime;
+
+ struct TraceBuffer {
+ static constexpr char const kTraceNamePrefix[] = "-alarm in:";
+ static constexpr char const kTraceNameSeparator[] = " for vs:";
+ static constexpr size_t kMaxNamePrint = 4;
+ static constexpr size_t kNumTsPrinted = 2;
+ static constexpr size_t maxlen = kMaxNamePrint + arrayLen(kTraceNamePrefix) +
+ arrayLen(kTraceNameSeparator) - 1 + (kNumTsPrinted * max64print);
+ std::array<char, maxlen> str_buffer;
+ void note(std::string_view name, nsecs_t in, nsecs_t vs);
+ } mTraceBuffer GUARDED_BY(mMutex);
};
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index e8c47a5..ac32633 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -23,28 +23,35 @@
#include "VSyncPredictor.h"
#include <android-base/logging.h>
#include <cutils/compiler.h>
+#include <cutils/properties.h>
#include <utils/Log.h>
#include <utils/Trace.h>
#include <algorithm>
#include <chrono>
#include <sstream>
-#include "SchedulerUtils.h"
namespace android::scheduler {
-static auto constexpr kNeedsSamplesTag = "SamplesRequested";
+
static auto constexpr kMaxPercent = 100u;
VSyncPredictor::~VSyncPredictor() = default;
VSyncPredictor::VSyncPredictor(nsecs_t idealPeriod, size_t historySize,
size_t minimumSamplesForPrediction, uint32_t outlierTolerancePercent)
- : kHistorySize(historySize),
+ : mTraceOn(property_get_bool("debug.sf.vsp_trace", false)),
+ kHistorySize(historySize),
kMinimumSamplesForPrediction(minimumSamplesForPrediction),
kOutlierTolerancePercent(std::min(outlierTolerancePercent, kMaxPercent)),
mIdealPeriod(idealPeriod) {
resetModel();
}
+inline void VSyncPredictor::traceInt64If(const char* name, int64_t value) const {
+ if (CC_UNLIKELY(mTraceOn)) {
+ ATRACE_INT64(name, value);
+ }
+}
+
inline size_t VSyncPredictor::next(int i) const {
return (i + 1) % timestamps.size();
}
@@ -68,7 +75,7 @@
std::lock_guard<std::mutex> lk(mMutex);
if (!validate(timestamp)) {
- ALOGW("timestamp was too far off the last known timestamp");
+ ALOGV("timestamp was too far off the last known timestamp");
return;
}
@@ -114,6 +121,8 @@
static constexpr int kScalingFactor = 10;
for (auto i = 0u; i < timestamps.size(); i++) {
+ traceInt64If("VSP-ts", timestamps[i]);
+
vsyncTS[i] = timestamps[i] - oldest_ts;
ordinals[i] = ((vsyncTS[i] + (currentPeriod / 2)) / currentPeriod) * kScalingFactor;
}
@@ -140,6 +149,9 @@
nsecs_t const anticipatedPeriod = top / bottom * kScalingFactor;
nsecs_t const intercept = meanTS - (anticipatedPeriod * meanOrdinal / kScalingFactor);
+ traceInt64If("VSP-period", anticipatedPeriod);
+ traceInt64If("VSP-intercept", intercept);
+
it->second = {anticipatedPeriod, intercept};
ALOGV("model update ts: %" PRId64 " slope: %" PRId64 " intercept: %" PRId64, timestamp,
@@ -152,6 +164,7 @@
auto const [slope, intercept] = getVSyncPredictionModel(lk);
if (timestamps.empty()) {
+ traceInt64If("VSP-mode", 1);
auto const knownTimestamp = mKnownTimestamp ? *mKnownTimestamp : timePoint;
auto const numPeriodsOut = ((timePoint - knownTimestamp) / mIdealPeriod) + 1;
return knownTimestamp + numPeriodsOut * mIdealPeriod;
@@ -164,6 +177,10 @@
auto const ordinalRequest = (timePoint - zeroPoint + slope) / slope;
auto const prediction = (ordinalRequest * slope) + intercept + oldest;
+ traceInt64If("VSP-mode", 0);
+ traceInt64If("VSP-timePoint", timePoint);
+ traceInt64If("VSP-prediction", prediction);
+
auto const printer = [&, slope = slope, intercept = intercept] {
std::stringstream str;
str << "prediction made from: " << timePoint << "prediction: " << prediction << " (+"
@@ -227,7 +244,7 @@
}
}
- ATRACE_INT(kNeedsSamplesTag, needsMoreSamples);
+ ATRACE_INT("VSP-moreSamples", needsMoreSamples);
return needsMoreSamples;
}
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h
index 41e5469..e366555 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.h
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h
@@ -20,6 +20,7 @@
#include <mutex>
#include <unordered_map>
#include <vector>
+#include "SchedulerUtils.h"
#include "VSyncTracker.h"
namespace android::scheduler {
@@ -64,6 +65,9 @@
VSyncPredictor& operator=(VSyncPredictor const&) = delete;
void clearTimestamps() REQUIRES(mMutex);
+ inline void traceInt64If(const char* name, int64_t value) const;
+ bool const mTraceOn;
+
size_t const kHistorySize;
size_t const kMinimumSamplesForPrediction;
size_t const kOutlierTolerancePercent;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 6d18922..8c271f9 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -353,6 +353,9 @@
property_get("debug.sf.luma_sampling", value, "1");
mLumaSampling = atoi(value);
+ property_get("debug.sf.disable_client_composition_cache", value, "1");
+ mDisableClientCompositionCache = atoi(value);
+
// We should be reading 'persist.sys.sf.color_saturation' here
// but since /data may be encrypted, we need to wait until after vold
// comes online to attempt to read the property. The property is
@@ -1893,13 +1896,19 @@
mHadClientComposition =
std::any_of(mDisplays.cbegin(), mDisplays.cend(), [](const auto& tokenDisplayPair) {
auto& displayDevice = tokenDisplayPair.second;
- return displayDevice->getCompositionDisplay()->getState().usesClientComposition;
+ return displayDevice->getCompositionDisplay()->getState().usesClientComposition &&
+ !displayDevice->getCompositionDisplay()->getState().reusedClientComposition;
});
mHadDeviceComposition =
std::any_of(mDisplays.cbegin(), mDisplays.cend(), [](const auto& tokenDisplayPair) {
auto& displayDevice = tokenDisplayPair.second;
return displayDevice->getCompositionDisplay()->getState().usesDeviceComposition;
});
+ mReusedClientComposition =
+ std::any_of(mDisplays.cbegin(), mDisplays.cend(), [](const auto& tokenDisplayPair) {
+ auto& displayDevice = tokenDisplayPair.second;
+ return displayDevice->getCompositionDisplay()->getState().reusedClientComposition;
+ });
mVSyncModulator->onRefreshed(mHadClientComposition);
@@ -2079,6 +2088,10 @@
mTimeStats->incrementClientCompositionFrames();
}
+ if (mReusedClientComposition) {
+ mTimeStats->incrementClientCompositionReusedFrames();
+ }
+
mTimeStats->setPresentFenceGlobal(presentFenceTime);
if (displayDevice && getHwComposer().isConnected(*displayDevice->getId()) &&
@@ -5408,7 +5421,7 @@
const auto& displayViewport = renderArea.getDisplayViewport();
renderengine::DisplaySettings clientCompositionDisplay;
- std::vector<renderengine::LayerSettings> clientCompositionLayers;
+ std::vector<compositionengine::LayerFE::LayerSettings> clientCompositionLayers;
// assume that bounds are never offset, and that they are the same as the
// buffer bounds.
@@ -5469,7 +5482,7 @@
const float alpha = RenderArea::getCaptureFillValue(renderArea.getCaptureFill());
- renderengine::LayerSettings fillLayer;
+ compositionengine::LayerFE::LayerSettings fillLayer;
fillLayer.source.buffer.buffer = nullptr;
fillLayer.source.solidColor = half3(0.0, 0.0, 0.0);
fillLayer.geometry.boundaries = FloatRect(0.0, 0.0, 1.0, 1.0);
@@ -5490,7 +5503,7 @@
};
auto result = layer->prepareClientComposition(targetSettings);
if (result) {
- std::optional<renderengine::LayerSettings> shadowLayer =
+ std::optional<compositionengine::LayerFE::LayerSettings> shadowLayer =
layer->prepareShadowClientComposition(*result, displayViewport,
clientCompositionDisplay.outputDataspace);
if (shadowLayer) {
@@ -5500,13 +5513,20 @@
}
});
+ std::vector<const renderengine::LayerSettings*> clientCompositionLayerPointers;
+ clientCompositionLayers.reserve(clientCompositionLayers.size());
+ std::transform(clientCompositionLayers.begin(), clientCompositionLayers.end(),
+ std::back_inserter(clientCompositionLayerPointers),
+ [](compositionengine::LayerFE::LayerSettings& settings)
+ -> renderengine::LayerSettings* { return &settings; });
+
clientCompositionDisplay.clearRegion = clearRegion;
// Use an empty fence for the buffer fence, since we just created the buffer so
// there is no need for synchronization with the GPU.
base::unique_fd bufferFence;
base::unique_fd drawFence;
getRenderEngine().useProtectedContext(false);
- getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayers, buffer,
+ getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buffer,
/*useFramebufferCache=*/false, std::move(bufferFence), &drawFence);
*outSyncFd = drawFence.release();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 7f7d8da..f8980a5 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -323,6 +323,10 @@
// Inherit from ClientCache::ErasedRecipient
void bufferErased(const client_cache_t& clientCacheId) override;
+ // If set, disables reusing client composition buffers. This can be set by
+ // debug.sf.disable_client_composition_cache
+ bool mDisableClientCompositionCache = false;
+
private:
friend class BufferLayer;
friend class BufferQueueLayer;
@@ -987,6 +991,10 @@
// Note that it is possible for a frame to be composed via both client and device
// composition, for example in the case of overlays.
bool mHadDeviceComposition = false;
+ // True if in the previous frame, the client composition was skipped by reusing the buffer
+ // used in a previous composition. This can happed if the client composition requests
+ // did not change.
+ bool mReusedClientComposition = false;
enum class BootStage {
BOOTLOADER,
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 7c824ec..12c98da 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -248,6 +248,15 @@
mTimeStats.clientCompositionFrames++;
}
+void TimeStats::incrementClientCompositionReusedFrames() {
+ if (!mEnabled.load()) return;
+
+ ATRACE_CALL();
+
+ std::lock_guard<std::mutex> lock(mMutex);
+ mTimeStats.clientCompositionReusedFrames++;
+}
+
static int32_t msBetween(nsecs_t start, nsecs_t end) {
int64_t delta = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::nanoseconds(end - start))
@@ -762,6 +771,7 @@
mTimeStats.totalFrames = 0;
mTimeStats.missedFrames = 0;
mTimeStats.clientCompositionFrames = 0;
+ mTimeStats.clientCompositionReusedFrames = 0;
mTimeStats.displayOnTime = 0;
mTimeStats.presentToPresent.hist.clear();
mTimeStats.frameDuration.hist.clear();
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index cf1c3c6..71f06af 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -51,6 +51,7 @@
virtual void incrementTotalFrames() = 0;
virtual void incrementMissedFrames() = 0;
virtual void incrementClientCompositionFrames() = 0;
+ virtual void incrementClientCompositionReusedFrames() = 0;
// Records the start and end times for a frame.
// The start time is the same as the beginning of a SurfaceFlinger
@@ -189,6 +190,7 @@
void incrementTotalFrames() override;
void incrementMissedFrames() override;
void incrementClientCompositionFrames() override;
+ void incrementClientCompositionReusedFrames() override;
void recordFrameDuration(nsecs_t startTime, nsecs_t endTime) override;
void recordRenderEngineDuration(nsecs_t startTime, nsecs_t endTime) override;
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index 7e43880..0ba90e2 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -102,6 +102,7 @@
StringAppendF(&result, "totalFrames = %d\n", totalFrames);
StringAppendF(&result, "missedFrames = %d\n", missedFrames);
StringAppendF(&result, "clientCompositionFrames = %d\n", clientCompositionFrames);
+ StringAppendF(&result, "clientCompositionReusedFrames = %d\n", clientCompositionReusedFrames);
StringAppendF(&result, "displayOnTime = %" PRId64 " ms\n", displayOnTime);
StringAppendF(&result, "displayConfigStats is as below:\n");
for (const auto& [fps, duration] : refreshRateStats) {
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
index bd97ecc..702c50e 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -59,6 +59,7 @@
int32_t totalFrames = 0;
int32_t missedFrames = 0;
int32_t clientCompositionFrames = 0;
+ int32_t clientCompositionReusedFrames = 0;
int64_t displayOnTime = 0;
Histogram presentToPresent;
Histogram frameDuration;
diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
index 2bedd7d..e5a7774 100644
--- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter
+++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
@@ -1,5 +1,5 @@
{
"presubmit": {
- "filter": "*:-LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadius/2:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadius/3:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadiusChildCrop/2:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadiusChildCrop/3"
+ "filter": "*:-LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadius/2:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadius/3:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadiusChildCrop/2:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadiusChildCrop/3:MirrorLayerTest.MirrorBufferLayer"
}
}
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 8a762d4..98cc023 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -328,8 +328,9 @@
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillRepeatedly(
[](const renderengine::DisplaySettings& displaySettings,
- const std::vector<renderengine::LayerSettings>&, ANativeWindowBuffer*,
- const bool, base::unique_fd&&, base::unique_fd*) -> status_t {
+ const std::vector<const renderengine::LayerSettings*>&,
+ ANativeWindowBuffer*, const bool, base::unique_fd&&,
+ base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
@@ -377,8 +378,9 @@
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillRepeatedly(
[](const renderengine::DisplaySettings& displaySettings,
- const std::vector<renderengine::LayerSettings>&, ANativeWindowBuffer*,
- const bool, base::unique_fd&&, base::unique_fd*) -> status_t {
+ const std::vector<const renderengine::LayerSettings*>&,
+ ANativeWindowBuffer*, const bool, base::unique_fd&&,
+ base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
@@ -627,7 +629,7 @@
static void setupREBufferCompositionCommonCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillOnce([](const renderengine::DisplaySettings& displaySettings,
- const std::vector<renderengine::LayerSettings>& layerSettings,
+ const std::vector<const renderengine::LayerSettings*>& layerSettings,
ANativeWindowBuffer*, const bool, base::unique_fd&&,
base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
@@ -643,16 +645,16 @@
"verification lambda";
return NO_ERROR;
}
- renderengine::LayerSettings layer = layerSettings.back();
- EXPECT_THAT(layer.source.buffer.buffer, Not(IsNull()));
- EXPECT_THAT(layer.source.buffer.fence, Not(IsNull()));
- EXPECT_EQ(DEFAULT_TEXTURE_ID, layer.source.buffer.textureName);
- EXPECT_EQ(false, layer.source.buffer.isY410BT2020);
- EXPECT_EQ(true, layer.source.buffer.usePremultipliedAlpha);
- EXPECT_EQ(false, layer.source.buffer.isOpaque);
- EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius);
- EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace);
- EXPECT_EQ(LayerProperties::COLOR[3], layer.alpha);
+ const renderengine::LayerSettings* layer = layerSettings.back();
+ EXPECT_THAT(layer->source.buffer.buffer, Not(IsNull()));
+ EXPECT_THAT(layer->source.buffer.fence, Not(IsNull()));
+ EXPECT_EQ(DEFAULT_TEXTURE_ID, layer->source.buffer.textureName);
+ EXPECT_EQ(false, layer->source.buffer.isY410BT2020);
+ EXPECT_EQ(true, layer->source.buffer.usePremultipliedAlpha);
+ EXPECT_EQ(false, layer->source.buffer.isOpaque);
+ EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace);
+ EXPECT_EQ(LayerProperties::COLOR[3], layer->alpha);
return NO_ERROR;
});
}
@@ -676,7 +678,7 @@
static void setupREColorCompositionCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillOnce([](const renderengine::DisplaySettings& displaySettings,
- const std::vector<renderengine::LayerSettings>& layerSettings,
+ const std::vector<const renderengine::LayerSettings*>& layerSettings,
ANativeWindowBuffer*, const bool, base::unique_fd&&,
base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
@@ -692,14 +694,14 @@
"setupREColorCompositionCallExpectations verification lambda";
return NO_ERROR;
}
- renderengine::LayerSettings layer = layerSettings.back();
- EXPECT_THAT(layer.source.buffer.buffer, IsNull());
+ const renderengine::LayerSettings* layer = layerSettings.back();
+ EXPECT_THAT(layer->source.buffer.buffer, IsNull());
EXPECT_EQ(half3(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
LayerProperties::COLOR[2]),
- layer.source.solidColor);
- EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius);
- EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace);
- EXPECT_EQ(LayerProperties::COLOR[3], layer.alpha);
+ layer->source.solidColor);
+ EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace);
+ EXPECT_EQ(LayerProperties::COLOR[3], layer->alpha);
return NO_ERROR;
});
}
@@ -752,7 +754,7 @@
static void setupInsecureREBufferCompositionCommonCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillOnce([](const renderengine::DisplaySettings& displaySettings,
- const std::vector<renderengine::LayerSettings>& layerSettings,
+ const std::vector<const renderengine::LayerSettings*>& layerSettings,
ANativeWindowBuffer*, const bool, base::unique_fd&&,
base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
@@ -768,12 +770,12 @@
"verification lambda";
return NO_ERROR;
}
- renderengine::LayerSettings layer = layerSettings.back();
- EXPECT_THAT(layer.source.buffer.buffer, IsNull());
- EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), layer.source.solidColor);
- EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius);
- EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace);
- EXPECT_EQ(1.0f, layer.alpha);
+ const renderengine::LayerSettings* layer = layerSettings.back();
+ EXPECT_THAT(layer->source.buffer.buffer, IsNull());
+ EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), layer->source.solidColor);
+ EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace);
+ EXPECT_EQ(1.0f, layer->alpha);
return NO_ERROR;
});
}
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 33563ea..9680a17 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -25,6 +25,7 @@
#include <compositionengine/Display.h>
#include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/impl/OutputCompositionState.h>
#include <compositionengine/mock/DisplaySurface.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -1278,6 +1279,243 @@
}
/* ------------------------------------------------------------------------
+ * DisplayDevice::setProjection
+ */
+
+class DisplayDeviceSetProjectionTest : public DisplayTransactionTest {
+public:
+ static constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{777};
+ static constexpr bool DEFAULT_DISPLAY_IS_VIRTUAL = false;
+ static constexpr bool DEFAULT_DISPLAY_IS_PRIMARY = true;
+ static constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1080; // arbitrary
+ static constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1920; // arbitrary
+
+ static constexpr int32_t TRANSFORM_FLAGS_ROT_0 = 0;
+ static constexpr int32_t TRANSFORM_FLAGS_ROT_90 = HAL_TRANSFORM_ROT_90;
+ static constexpr int32_t TRANSFORM_FLAGS_ROT_180 = HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_FLIP_V;
+ static constexpr int32_t TRANSFORM_FLAGS_ROT_270 =
+ HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_ROT_90;
+
+ DisplayDeviceSetProjectionTest(ui::Size flingerDisplaySize, ui::Size hardwareDisplaySize,
+ ui::Rotation physicalOrientation)
+ : mFlingerDisplaySize(flingerDisplaySize),
+ mHardwareDisplaySize(hardwareDisplaySize),
+ mPhysicalOrientation(physicalOrientation),
+ mDisplayDevice(createDisplayDevice()) {}
+
+ sp<DisplayDevice> createDisplayDevice() {
+ // The DisplayDevice is required to have a framebuffer (behind the
+ // ANativeWindow interface) which uses the actual hardware display
+ // size.
+ EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(mHardwareDisplaySize.width), Return(0)));
+ EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(mHardwareDisplaySize.height), Return(0)));
+ EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT));
+ EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT));
+ EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64));
+ EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT));
+
+ return FakeDisplayDeviceInjector(mFlinger, DEFAULT_DISPLAY_ID, DEFAULT_DISPLAY_IS_VIRTUAL,
+ DEFAULT_DISPLAY_IS_PRIMARY)
+ .setNativeWindow(mNativeWindow)
+ .setPhysicalOrientation(mPhysicalOrientation)
+ .inject();
+ }
+
+ ui::Size SwapWH(const ui::Size size) const { return ui::Size(size.height, size.width); }
+
+ void setProjectionForRotation0() {
+ // A logical rotation of 0 uses the SurfaceFlinger display size
+ mDisplayDevice->setProjection(ui::ROTATION_0, Rect(mFlingerDisplaySize),
+ Rect(mFlingerDisplaySize));
+ }
+
+ void setProjectionForRotation90() {
+ // A logical rotation of 90 uses the SurfaceFlinger display size with
+ // the width/height swapped.
+ mDisplayDevice->setProjection(ui::ROTATION_90, Rect(SwapWH(mFlingerDisplaySize)),
+ Rect(SwapWH(mFlingerDisplaySize)));
+ }
+
+ void setProjectionForRotation180() {
+ // A logical rotation of 180 uses the SurfaceFlinger display size
+ mDisplayDevice->setProjection(ui::ROTATION_180, Rect(mFlingerDisplaySize),
+ Rect(mFlingerDisplaySize));
+ }
+
+ void setProjectionForRotation270() {
+ // A logical rotation of 270 uses the SurfaceFlinger display size with
+ // the width/height swapped.
+ mDisplayDevice->setProjection(ui::ROTATION_270, Rect(SwapWH(mFlingerDisplaySize)),
+ Rect(SwapWH(mFlingerDisplaySize)));
+ }
+
+ void expectStateForHardwareTransform0() {
+ const auto& compositionState = mDisplayDevice->getCompositionDisplay()->getState();
+ EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_0, mHardwareDisplaySize.width,
+ mHardwareDisplaySize.height),
+ compositionState.transform);
+ EXPECT_EQ(TRANSFORM_FLAGS_ROT_0, compositionState.orientation);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.scissor);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.frame);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.viewport);
+ EXPECT_EQ(false, compositionState.needsFiltering);
+ }
+
+ void expectStateForHardwareTransform90() {
+ const auto& compositionState = mDisplayDevice->getCompositionDisplay()->getState();
+ EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_90, mHardwareDisplaySize.width,
+ mHardwareDisplaySize.height),
+ compositionState.transform);
+ EXPECT_EQ(TRANSFORM_FLAGS_ROT_90, compositionState.orientation);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.scissor);
+ // For 90, the frame and viewport have the hardware display size width and height swapped
+ EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.frame);
+ EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.viewport);
+ EXPECT_EQ(false, compositionState.needsFiltering);
+ }
+
+ void expectStateForHardwareTransform180() {
+ const auto& compositionState = mDisplayDevice->getCompositionDisplay()->getState();
+ EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_180, mHardwareDisplaySize.width,
+ mHardwareDisplaySize.height),
+ compositionState.transform);
+ EXPECT_EQ(TRANSFORM_FLAGS_ROT_180, compositionState.orientation);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.scissor);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.frame);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.viewport);
+ EXPECT_EQ(false, compositionState.needsFiltering);
+ }
+
+ void expectStateForHardwareTransform270() {
+ const auto& compositionState = mDisplayDevice->getCompositionDisplay()->getState();
+ EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_270, mHardwareDisplaySize.width,
+ mHardwareDisplaySize.height),
+ compositionState.transform);
+ EXPECT_EQ(TRANSFORM_FLAGS_ROT_270, compositionState.orientation);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.scissor);
+ // For 270, the frame and viewport have the hardware display size width and height swapped
+ EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.frame);
+ EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.viewport);
+ EXPECT_EQ(false, compositionState.needsFiltering);
+ }
+
+ const ui::Size mFlingerDisplaySize;
+ const ui::Size mHardwareDisplaySize;
+ const ui::Rotation mPhysicalOrientation;
+ const sp<DisplayDevice> mDisplayDevice;
+};
+
+struct DisplayDeviceSetProjectionTest_Installed0 : public DisplayDeviceSetProjectionTest {
+ DisplayDeviceSetProjectionTest_Installed0()
+ : DisplayDeviceSetProjectionTest(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ ui::ROTATION_0) {}
+};
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed0, checkWith0OutputRotation) {
+ setProjectionForRotation0();
+ expectStateForHardwareTransform0();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed0, checkWith90OutputRotation) {
+ setProjectionForRotation90();
+ expectStateForHardwareTransform90();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed0, checkWith180OutputRotation) {
+ setProjectionForRotation180();
+ expectStateForHardwareTransform180();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed0, checkWith270OutputRotation) {
+ setProjectionForRotation270();
+ expectStateForHardwareTransform270();
+}
+
+struct DisplayDeviceSetProjectionTest_Installed90 : public DisplayDeviceSetProjectionTest {
+ DisplayDeviceSetProjectionTest_Installed90()
+ : DisplayDeviceSetProjectionTest(ui::Size(DEFAULT_DISPLAY_HEIGHT, DEFAULT_DISPLAY_WIDTH),
+ ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ ui::ROTATION_90) {}
+};
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed90, checkWith0OutputRotation) {
+ setProjectionForRotation0();
+ expectStateForHardwareTransform90();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed90, checkWith90OutputRotation) {
+ setProjectionForRotation90();
+ expectStateForHardwareTransform180();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed90, checkWith180OutputRotation) {
+ setProjectionForRotation180();
+ expectStateForHardwareTransform270();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed90, checkWith270OutputRotation) {
+ setProjectionForRotation270();
+ expectStateForHardwareTransform0();
+}
+
+struct DisplayDeviceSetProjectionTest_Installed180 : public DisplayDeviceSetProjectionTest {
+ DisplayDeviceSetProjectionTest_Installed180()
+ : DisplayDeviceSetProjectionTest(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ ui::ROTATION_180) {}
+};
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed180, checkWith0OutputRotation) {
+ setProjectionForRotation0();
+ expectStateForHardwareTransform180();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed180, checkWith90OutputRotation) {
+ setProjectionForRotation90();
+ expectStateForHardwareTransform270();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed180, checkWith180OutputRotation) {
+ setProjectionForRotation180();
+ expectStateForHardwareTransform0();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed180, checkWith270OutputRotation) {
+ setProjectionForRotation270();
+ expectStateForHardwareTransform90();
+}
+
+struct DisplayDeviceSetProjectionTest_Installed270 : public DisplayDeviceSetProjectionTest {
+ DisplayDeviceSetProjectionTest_Installed270()
+ : DisplayDeviceSetProjectionTest(ui::Size(DEFAULT_DISPLAY_HEIGHT, DEFAULT_DISPLAY_WIDTH),
+ ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ ui::ROTATION_270) {}
+};
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed270, checkWith0OutputRotation) {
+ setProjectionForRotation0();
+ expectStateForHardwareTransform270();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed270, checkWith90OutputRotation) {
+ setProjectionForRotation90();
+ expectStateForHardwareTransform0();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed270, checkWith180OutputRotation) {
+ setProjectionForRotation180();
+ expectStateForHardwareTransform90();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed270, checkWith270OutputRotation) {
+ setProjectionForRotation270();
+ expectStateForHardwareTransform180();
+}
+
+/* ------------------------------------------------------------------------
* SurfaceFlinger::getDisplayNativePrimaries
*/
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 9728c80..8ddb872 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -605,6 +605,11 @@
return *this;
}
+ auto& setPhysicalOrientation(ui::Rotation orientation) {
+ mCreationArgs.physicalOrientation = orientation;
+ return *this;
+ }
+
sp<DisplayDevice> inject() {
DisplayDeviceState state;
state.displayId = mCreationArgs.isVirtual ? std::nullopt : mCreationArgs.displayId;
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index 5044626..68e6697 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -44,6 +44,7 @@
using testing::_;
using testing::AnyNumber;
using testing::Contains;
+using testing::HasSubstr;
using testing::InSequence;
using testing::SizeIs;
using testing::StrEq;
@@ -305,6 +306,21 @@
EXPECT_EQ(CLIENT_COMPOSITION_FRAMES, globalProto.client_composition_frames());
}
+TEST_F(TimeStatsTest, canIncreaseClientCompositionReusedFrames) {
+ // this stat is not in the proto so verify by checking the string dump
+ constexpr size_t CLIENT_COMPOSITION_REUSED_FRAMES = 2;
+
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+ for (size_t i = 0; i < CLIENT_COMPOSITION_REUSED_FRAMES; i++) {
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionReusedFrames());
+ }
+
+ const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+ const std::string expectedResult =
+ "clientCompositionReusedFrames = " + std::to_string(CLIENT_COMPOSITION_REUSED_FRAMES);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+}
+
TEST_F(TimeStatsTest, canInsertGlobalPresentToPresent) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
@@ -649,6 +665,16 @@
EXPECT_EQ(0, globalProto.stats_size());
}
+TEST_F(TimeStatsTest, canClearClientCompositionSkippedFrames) {
+ // this stat is not in the proto so verify by checking the string dump
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionReusedFrames());
+ EXPECT_TRUE(inputCommand(InputCommand::CLEAR, FMT_STRING).empty());
+
+ const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+ EXPECT_THAT(result, HasSubstr("clientCompositionReusedFrames = 0"));
+}
+
TEST_F(TimeStatsTest, canDumpWithMaxLayers) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
index 9ada5ef..d1df08c 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
@@ -35,6 +35,7 @@
MOCK_METHOD0(incrementTotalFrames, void());
MOCK_METHOD0(incrementMissedFrames, void());
MOCK_METHOD0(incrementClientCompositionFrames, void());
+ MOCK_METHOD0(incrementClientCompositionReusedFrames, void());
MOCK_METHOD2(recordFrameDuration, void(nsecs_t, nsecs_t));
MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, nsecs_t));
MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, const std::shared_ptr<FenceTime>&));