Merge "Reduce indentation of a method"
diff --git a/aidl/binder/android/os/PersistableBundle.aidl b/aidl/binder/android/os/PersistableBundle.aidl
index 94e8607..493ecb4 100644
--- a/aidl/binder/android/os/PersistableBundle.aidl
+++ b/aidl/binder/android/os/PersistableBundle.aidl
@@ -17,4 +17,4 @@
package android.os;
-parcelable PersistableBundle cpp_header "binder/PersistableBundle.h";
+@JavaOnlyStableParcelable parcelable PersistableBundle cpp_header "binder/PersistableBundle.h";
diff --git a/cmds/cmd/cmd.cpp b/cmds/cmd/cmd.cpp
index 7b4aeb2..8dad475 100644
--- a/cmds/cmd/cmd.cpp
+++ b/cmds/cmd/cmd.cpp
@@ -223,7 +223,8 @@
sp<MyResultReceiver> result = new MyResultReceiver();
#if DEBUG
- ALOGD("cmd: Invoking %s in=%d, out=%d, err=%d", cmd, in, out, err);
+ ALOGD("cmd: Invoking %.*s in=%d, out=%d, err=%d",
+ static_cast<int>(cmd.size()), cmd.data(), in, out, err);
#endif
// TODO: block until a result is returned to MyResultReceiver.
diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto
index 7f2f949..b574098 100644
--- a/cmds/surfacereplayer/proto/src/trace.proto
+++ b/cmds/surfacereplayer/proto/src/trace.proto
@@ -51,6 +51,7 @@
RelativeParentChange relative_parent = 18;
DetachChildrenChange detach_children = 19;
ReparentChildrenChange reparent_children = 20;
+ BackgroundBlurRadiusChange background_blur_radius = 21;
ShadowRadiusChange shadow_radius = 22;
}
}
@@ -73,6 +74,10 @@
required float corner_radius = 1;
}
+message BackgroundBlurRadiusChange {
+ required float background_blur_radius = 1;
+}
+
message LayerChange {
required uint32 layer = 1;
}
diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp
index 675aad6..2b5667d 100644
--- a/cmds/surfacereplayer/replayer/Replayer.cpp
+++ b/cmds/surfacereplayer/replayer/Replayer.cpp
@@ -510,6 +510,14 @@
t.setCornerRadius(mLayers[id], cc.corner_radius());
}
+void Replayer::setBackgroundBlurRadius(SurfaceComposerClient::Transaction& t,
+ layer_id id, const BackgroundBlurRadiusChange& cc) {
+ ALOGV("Layer %d: Setting Background Blur Radius -- backgroundBlurRadius=%d", id,
+ cc.background_blur_radius());
+
+ t.setBackgroundBlurRadius(mLayers[id], cc.background_blur_radius());
+}
+
void Replayer::setMatrix(SurfaceComposerClient::Transaction& t,
layer_id id, const MatrixChange& mc) {
ALOGV("Layer %d: Setting Matrix -- dsdx=%f, dtdx=%f, dsdy=%f, dtdy=%f", id, mc.dsdx(),
diff --git a/cmds/surfacereplayer/replayer/Replayer.h b/cmds/surfacereplayer/replayer/Replayer.h
index b547834..95857e1 100644
--- a/cmds/surfacereplayer/replayer/Replayer.h
+++ b/cmds/surfacereplayer/replayer/Replayer.h
@@ -94,6 +94,8 @@
layer_id id, const CropChange& cc);
void setCornerRadius(SurfaceComposerClient::Transaction& t,
layer_id id, const CornerRadiusChange& cc);
+ void setBackgroundBlurRadius(SurfaceComposerClient::Transaction& t,
+ layer_id id, const BackgroundBlurRadiusChange& cc);
void setMatrix(SurfaceComposerClient::Transaction& t,
layer_id id, const MatrixChange& mc);
void setOverrideScalingMode(SurfaceComposerClient::Transaction& t,
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.hardware.telephony.cdma.xml b/data/etc/android.hardware.telephony.cdma.xml
index b598f68..082378d 100644
--- a/data/etc/android.hardware.telephony.cdma.xml
+++ b/data/etc/android.hardware.telephony.cdma.xml
@@ -18,5 +18,4 @@
<permissions>
<feature name="android.hardware.telephony" />
<feature name="android.hardware.telephony.cdma" />
- <feature name="android.hardware.telephony.data" />
</permissions>
diff --git a/data/etc/android.hardware.telephony.gsm.xml b/data/etc/android.hardware.telephony.gsm.xml
index fe8a5cf..7927fa8 100644
--- a/data/etc/android.hardware.telephony.gsm.xml
+++ b/data/etc/android.hardware.telephony.gsm.xml
@@ -18,5 +18,4 @@
<permissions>
<feature name="android.hardware.telephony" />
<feature name="android.hardware.telephony.gsm" />
- <feature name="android.hardware.telephony.data" />
</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/docs/images/camera2/metadata/android.scaler.rotateAndCrop/crop-region-rotate-90-43-ratio.png b/docs/images/camera2/metadata/android.scaler.rotateAndCrop/crop-region-rotate-90-43-ratio.png
new file mode 100644
index 0000000..2633996
--- /dev/null
+++ b/docs/images/camera2/metadata/android.scaler.rotateAndCrop/crop-region-rotate-90-43-ratio.png
Binary files differ
diff --git a/include/android/bitmap.h b/include/android/bitmap.h
index 41718b2..571a5ca 100644
--- a/include/android/bitmap.h
+++ b/include/android/bitmap.h
@@ -26,6 +26,7 @@
#ifndef ANDROID_BITMAP_H
#define ANDROID_BITMAP_H
+#include <stdbool.h>
#include <stdint.h>
#include <jni.h>
@@ -78,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. */
@@ -89,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;
@@ -133,6 +144,103 @@
*/
int AndroidBitmap_unlockPixels(JNIEnv* env, jobject jbitmap);
+#if __ANDROID_API__ >= 30
+
+// Note: these values match android.graphics.Bitmap#compressFormat.
+
+/**
+ * Specifies the formats that can be compressed to with
+ * {@link AndroidBitmap_compress}.
+ */
+enum AndroidBitmapCompressFormat {
+ /**
+ * Compress to the JPEG format. quality of 0 means
+ * compress for the smallest size. 100 means compress for max
+ * visual quality.
+ */
+ ANDROID_BITMAP_COMPRESS_FORMAT_JPEG = 0,
+ /**
+ * Compress to the PNG format. PNG is lossless, so quality is
+ * ignored.
+ */
+ ANDROID_BITMAP_COMPRESS_FORMAT_PNG = 1,
+ /**
+ * Compress to the WEBP lossy format. quality of 0 means
+ * compress for the smallest size. 100 means compress for max
+ * visual quality.
+ */
+ ANDROID_BITMAP_COMPRESS_FORMAT_WEBP_LOSSY = 3,
+ /**
+ * Compress to the WEBP lossless format. quality refers to how
+ * much effort to put into compression. A value of 0 means to
+ * compress quickly, resulting in a relatively large file size.
+ * 100 means to spend more time compressing, resulting in a
+ * smaller file.
+ */
+ ANDROID_BITMAP_COMPRESS_FORMAT_WEBP_LOSSLESS = 4,
+};
+
+/**
+ * User-defined function for writing the output of compression.
+ *
+ * @param userContext Pointer to user-defined data passed to
+ * {@link AndroidBitmap_compress}.
+ * @param data Compressed data of |size| bytes to write.
+ * @param size Length in bytes of data to write.
+ * @return Whether the operation succeeded.
+ */
+typedef bool (*AndroidBitmap_CompressWriteFunc)(void* userContext,
+ const void* data,
+ size_t size) __INTRODUCED_IN(30);
+
+/**
+ * Compress |pixels| as described by |info|.
+ *
+ * @param info Description of the pixels to compress.
+ * @param dataspace {@link ADataSpace} describing the color space of the
+ * pixels.
+ * @param pixels Pointer to pixels to compress.
+ * @param format (@link AndroidBitmapCompressFormat} to compress to.
+ * @param quality Hint to the compressor, 0-100. The value is interpreted
+ * differently depending on the
+ * {@link AndroidBitmapCompressFormat}.
+ * @param userContext User-defined data which will be passed to the supplied
+ * {@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
+ * written. May be called more than once for each call to this method.
+ * May not be null.
+ * @return AndroidBitmap functions result code.
+ */
+int AndroidBitmap_compress(const AndroidBitmapInfo* info,
+ int32_t dataspace,
+ const void* pixels,
+ int32_t format, int32_t quality,
+ void* userContext,
+ 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
+
#ifdef __cplusplus
}
#endif
diff --git a/include/android/imagedecoder.h b/include/android/imagedecoder.h
index 50daaba..da324b8 100644
--- a/include/android/imagedecoder.h
+++ b/include/android/imagedecoder.h
@@ -133,7 +133,7 @@
/**
* Choose the desired output format.
*
- * @param format AndroidBitmapFormat to use
+ * @param format {@link AndroidBitmapFormat} to use for the output.
* @return {@link ANDROID_IMAGE_DECODER_SUCCESS} if the format is compatible
* with the image and {@link ANDROID_IMAGE_DECODER_INVALID_CONVERSION}
* otherwise. In the latter case, the AImageDecoder uses the
@@ -143,23 +143,39 @@
int AImageDecoder_setAndroidBitmapFormat(AImageDecoder*,
int32_t format) __INTRODUCED_IN(30);
-/*
- * Choose the desired output format.
+/**
+ * Specify whether the output's pixels should be unpremultiplied.
*
- * Must be one of:
- * {@link ANDROID_BITMAP_FLAGS_ALPHA_PREMUL}
- * {@link ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE}
- * {@link ANDROID_BITMAP_FLAGS_ALPHA_UNPREMUL}
+ * By default, the decoder will premultiply the pixels, if they have alpha. Pass
+ * false to this method to leave them unpremultiplied. This has no effect on an
+ * opaque image.
*
- * Note: An OPAQUE image may be set to any of them.
- * A non-OPAQUE image may not be set to OPAQUE
- *
+ * @param required Pass true to leave the pixels unpremultiplied.
* @return - {@link ANDROID_IMAGE_DECODER_SUCCESS} on success
* - {@link ANDROID_IMAGE_DECODER_INVALID_CONVERSION} if the conversion
* is not possible
* - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER} for bad parameters
*/
-int AImageDecoder_setAlphaFlags(AImageDecoder*, int alphaFlags) __INTRODUCED_IN(30);
+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.
@@ -180,8 +196,30 @@
* pointer is null, width or height is <= 0, or any existing crop is
* not contained by the image dimensions.
*/
-int AImageDecoder_setTargetSize(AImageDecoder*, int width, int height) __INTRODUCED_IN(30);
+int AImageDecoder_setTargetSize(AImageDecoder*, int32_t width, int32_t 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,
+ int32_t* width, int32_t* height) __INTRODUCED_IN(30);
/**
* Specify how to crop the output after scaling (if any).
*
@@ -238,18 +276,12 @@
const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
/**
- * Report whether the encoded image represents an animation.
- */
-bool AImageDecoderHeaderInfo_isAnimated(
- const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
-
-/**
- * Report the AndroidBitmapFormat the AImageDecoder will decode to
+ * Report the {@link AndroidBitmapFormat} 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 does not indicate the
* encoded format of the image.
*/
-AndroidBitmapFormat AImageDecoderHeaderInfo_getAndroidBitmapFormat(
+int32_t AImageDecoderHeaderInfo_getAndroidBitmapFormat(
const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
/**
@@ -264,6 +296,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.
@@ -280,7 +331,8 @@
* {@link AImageDecoder_getMinimumStride}.
* @param size Size of the pixel buffer in bytes. Must be at least
* stride * (height - 1) +
- * {@link AImageDecoder_getMinimumStride}.
+ * {@link AImageDecoder_getMinimumStride}. Must also be a multiple
+ * of the bytes per pixel of the {@link AndroidBitmapFormat}.
* @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success, or an error code
* from the same enum describing the failure.
*/
diff --git a/include/android/input.h b/include/android/input.h
index f51cd79..dbfd61e 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -793,6 +793,8 @@
AMOTION_EVENT_TOOL_TYPE_MOUSE = 3,
/** eraser */
AMOTION_EVENT_TOOL_TYPE_ERASER = 4,
+ /** palm */
+ AMOTION_EVENT_TOOL_TYPE_PALM = 5,
};
/**
diff --git a/include/android/sensor.h b/include/android/sensor.h
index 3ebe79f..12c00ad 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -245,6 +245,10 @@
* {@link ASENSOR_TYPE_ACCELEROMETER_UNCALIBRATED}
*/
ASENSOR_TYPE_ACCELEROMETER_UNCALIBRATED = 35,
+ /**
+ * {@link ASENSOR_TYPE_HINGE_ANGLE}
+ */
+ ASENSOR_TYPE_HINGE_ANGLE = 36,
};
/**
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index 31abb66..eeb8330 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -407,6 +407,33 @@
#endif // __ANDROID_API__ >= 29
+#if __ANDROID_API__ >= 30
+
+/*
+ * Sets the intended frame rate for |surface_control|.
+ *
+ * On devices that are capable of running the display at different refresh rates, the system may
+ * choose a display refresh rate to better match this surface's frame rate. Usage of this API won't
+ * directly affect the application's frame production pipeline. However, because the system may
+ * change the display refresh rate, calls to this function may result in changes to Choreographer
+ * callback timings, and changes to the time interval at which the system releases buffers back to
+ * the application.
+ *
+ * |frameRate| is the intended frame rate of this surface, in frames per second. 0 is a special
+ * value that indicates the app will accept the system's choice for the display frame rate, which is
+ * the default behavior if this function isn't called. The frameRate param does *not* need to be a
+ * valid refresh rate for this device's display - e.g., it's fine to pass 30fps to a device that can
+ * only run the display at 60fps.
+ *
+ * Available since API level 30.
+ */
+void ASurfaceTransaction_setFrameRate(ASurfaceTransaction* transaction,
+ ASurfaceControl* surface_control,
+ float frameRate)
+ __INTRODUCED_IN(30);
+
+#endif // __ANDROID_API__ >= 30
+
__END_DECLS
#endif // ANDROID_SURFACE_CONTROL_H
diff --git a/libs/binder/BufferedTextOutput.cpp b/libs/binder/BufferedTextOutput.cpp
index fb424fd..824b56b 100644
--- a/libs/binder/BufferedTextOutput.cpp
+++ b/libs/binder/BufferedTextOutput.cpp
@@ -49,9 +49,10 @@
}
status_t append(const char* txt, size_t len) {
+ if (len > SIZE_MAX - bufferPos) return NO_MEMORY; // overflow
if ((len+bufferPos) > bufferSize) {
+ if ((len + bufferPos) > SIZE_MAX / 3) return NO_MEMORY; // overflow
size_t newSize = ((len+bufferPos)*3)/2;
- if (newSize < (len+bufferPos)) return NO_MEMORY; // overflow
void* b = realloc(buffer, newSize);
if (!b) return NO_MEMORY;
buffer = (char*)b;
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index a9f8ae6..994e3b9 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -422,8 +422,10 @@
const sp<ProcessState> proc(ProcessState::self());
// grow objects
if (mObjectsCapacity < mObjectsSize + numObjects) {
+ if ((size_t) numObjects > SIZE_MAX - mObjectsSize) return NO_MEMORY; // overflow
+ if (mObjectsSize + numObjects > SIZE_MAX / 3) return NO_MEMORY; // overflow
size_t newSize = ((mObjectsSize + numObjects)*3)/2;
- if (newSize*sizeof(binder_size_t) < mObjectsSize) return NO_MEMORY; // overflow
+ if (newSize > SIZE_MAX / sizeof(binder_size_t)) return NO_MEMORY; // overflow
binder_size_t *objects =
(binder_size_t*)realloc(mObjects, newSize*sizeof(binder_size_t));
if (objects == (binder_size_t*)nullptr) {
@@ -1276,8 +1278,10 @@
if (err != NO_ERROR) return err;
}
if (!enoughObjects) {
+ if (mObjectsSize > SIZE_MAX - 2) return NO_MEMORY; // overflow
+ if ((mObjectsSize + 2) > SIZE_MAX / 3) return NO_MEMORY; // overflow
size_t newSize = ((mObjectsSize+2)*3)/2;
- if (newSize*sizeof(binder_size_t) < mObjectsSize) return NO_MEMORY; // overflow
+ if (newSize > SIZE_MAX / sizeof(binder_size_t)) return NO_MEMORY; // overflow
binder_size_t* objects = (binder_size_t*)realloc(mObjects, newSize*sizeof(binder_size_t));
if (objects == nullptr) return NO_MEMORY;
mObjects = objects;
@@ -2405,6 +2409,8 @@
return BAD_VALUE;
}
+ if (len > SIZE_MAX - mDataSize) return NO_MEMORY; // overflow
+ if (mDataSize + len > SIZE_MAX / 3) return NO_MEMORY; // overflow
size_t newSize = ((mDataSize+len)*3)/2;
return (newSize <= mDataSize)
? (status_t) NO_MEMORY
diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp
index ebd08b2..daaaa5a 100644
--- a/libs/binder/ndk/test/Android.bp
+++ b/libs/binder/ndk/test/Android.bp
@@ -90,8 +90,7 @@
aidl_interface {
name: "IBinderVendorDoubleLoadTest",
- // TODO(b/119771576): only vendor is needed
- vendor_available: true,
+ vendor: true,
srcs: [
"IBinderVendorDoubleLoadTest.aidl",
],
diff --git a/libs/gralloc/types/Gralloc4.cpp b/libs/gralloc/types/Gralloc4.cpp
index 4851b44..4e8569f 100644
--- a/libs/gralloc/types/Gralloc4.cpp
+++ b/libs/gralloc/types/Gralloc4.cpp
@@ -42,6 +42,7 @@
using aidl::android::hardware::graphics::common::StandardMetadataType;
using aidl::android::hardware::graphics::common::XyColor;
+using BufferDescriptorInfo = android::hardware::graphics::mapper::V4_0::IMapper::BufferDescriptorInfo;
using MetadataType = android::hardware::graphics::mapper::V4_0::IMapper::MetadataType;
namespace android {
@@ -195,15 +196,32 @@
status_t validateMetadataType(InputHidlVec* input, const MetadataType& expectedMetadataType);
/**
- * encode is the main encoding function. It takes in T and uses the encodeHelper function to turn T
- * into the hidl_vec byte stream.
+ * encode/encodeMetadata are the main encoding functions. They take in T and uses the encodeHelper
+ * function to turn T into the hidl_vec byte stream.
*
- * This function first calls the encodeHelper function to determine how large the hidl_vec
- * needs to be. It resizes the hidl_vec. Finally, it reruns the encodeHelper function which
+ * These functions first call the encodeHelper function to determine how large the hidl_vec
+ * needs to be. They resize the hidl_vec. Finally, it reruns the encodeHelper function which
* encodes T into the hidl_vec byte stream.
*/
template <class T>
-status_t encode(const MetadataType& metadataType, const T& input, hidl_vec<uint8_t>* output,
+status_t encode(const T& input, hidl_vec<uint8_t>* output, EncodeHelper<T> encodeHelper) {
+ OutputHidlVec outputHidlVec{output};
+
+ status_t err = encodeHelper(input, &outputHidlVec);
+ if (err) {
+ return err;
+ }
+
+ err = outputHidlVec.resize();
+ if (err) {
+ return err;
+ }
+
+ return encodeHelper(input, &outputHidlVec);
+}
+
+template <class T>
+status_t encodeMetadata(const MetadataType& metadataType, const T& input, hidl_vec<uint8_t>* output,
EncodeHelper<T> encodeHelper) {
OutputHidlVec outputHidlVec{output};
@@ -231,21 +249,42 @@
}
template <class T>
-status_t encodeOptional(const MetadataType& metadataType, const std::optional<T>& input,
+status_t encodeOptionalMetadata(const MetadataType& metadataType, const std::optional<T>& input,
hidl_vec<uint8_t>* output, EncodeHelper<T> encodeHelper) {
if (!input) {
return NO_ERROR;
}
- return encode(metadataType, *input, output, encodeHelper);
+ return encodeMetadata(metadataType, *input, output, encodeHelper);
}
/**
- * decode is the main decode function. It takes in a hidl_vec and uses the decodeHelper function to
- * turn the hidl_vec byte stream into T. If an error occurs, the errorHandler function cleans up
- * T.
+ * decode/decodeMetadata are the main decoding functions. They take in a hidl_vec and use the
+ * decodeHelper function to turn the hidl_vec byte stream into T. If an error occurs, the
+ * errorHandler function cleans up T.
*/
template <class T>
-status_t decode(const MetadataType& metadataType, const hidl_vec<uint8_t>& input, T* output,
+status_t decode(const hidl_vec<uint8_t>& input, T* output, DecodeHelper<T> decodeHelper,
+ ErrorHandler<T> errorHandler = nullptr) {
+ InputHidlVec inputHidlVec{&input};
+
+ status_t err = decodeHelper(&inputHidlVec, output);
+ if (err) {
+ return err;
+ }
+
+ err = inputHidlVec.hasRemainingData();
+ if (err) {
+ if (errorHandler) {
+ errorHandler(output);
+ }
+ return BAD_VALUE;
+ }
+
+ return NO_ERROR;
+}
+
+template <class T>
+status_t decodeMetadata(const MetadataType& metadataType, const hidl_vec<uint8_t>& input, T* output,
DecodeHelper<T> decodeHelper, ErrorHandler<T> errorHandler = nullptr) {
InputHidlVec inputHidlVec{&input};
@@ -271,7 +310,7 @@
}
template <class T>
-status_t decodeOptional(const MetadataType& metadataType, const hidl_vec<uint8_t>& input,
+status_t decodeOptionalMetadata(const MetadataType& metadataType, const hidl_vec<uint8_t>& input,
std::optional<T>* output, DecodeHelper<T> decodeHelper) {
if (!output) {
return BAD_VALUE;
@@ -281,7 +320,7 @@
return NO_ERROR;
}
T tmp;
- status_t err = decode(metadataType, input, &tmp, decodeHelper);
+ status_t err = decodeMetadata(metadataType, input, &tmp, decodeHelper);
if (!err) {
*output = tmp;
}
@@ -520,6 +559,66 @@
return decodeInteger<int32_t>(input, &output->bottom);
}
+status_t encodeBufferDescriptorInfoHelper(const BufferDescriptorInfo& input,
+ OutputHidlVec* output) {
+ status_t err = encodeString(input.name, output);
+ if (err) {
+ return err;
+ }
+ err = encodeInteger<uint32_t>(input.width, output);
+ if (err) {
+ return err;
+ }
+ err = encodeInteger<uint32_t>(input.height, output);
+ if (err) {
+ return err;
+ }
+ err = encodeInteger<uint32_t>(input.layerCount, output);
+ if (err) {
+ return err;
+ }
+ err = encodeInteger<int32_t>(static_cast<int32_t>(input.format), output);
+ if (err) {
+ return err;
+ }
+ err = encodeInteger<uint64_t>(input.usage, output);
+ if (err) {
+ return err;
+ }
+ return encodeInteger<uint64_t>(input.reservedSize, output);
+}
+
+status_t decodeBufferDescriptorInfoHelper(InputHidlVec* input, BufferDescriptorInfo* output) {
+ std::string name;
+ status_t err = decodeString(input, &name);
+ if (err) {
+ return err;
+ }
+ output->name = name;
+
+ err = decodeInteger<uint32_t>(input, &output->width);
+ if (err) {
+ return err;
+ }
+ err = decodeInteger<uint32_t>(input, &output->height);
+ if (err) {
+ return err;
+ }
+ err = decodeInteger<uint32_t>(input, &output->layerCount);
+ if (err) {
+ return err;
+ }
+ err = decodeInteger<int32_t>(input, reinterpret_cast<int32_t*>(&output->format));
+ if (err) {
+ return err;
+ }
+ err = decodeInteger<uint64_t>(input, &output->usage);
+ if (err) {
+ return err;
+ }
+ return decodeInteger<uint64_t>(input, &output->reservedSize);
+}
+
status_t encodePlaneLayoutComponent(const PlaneLayoutComponent& input, OutputHidlVec* output) {
if (!output) {
return BAD_VALUE;
@@ -799,260 +898,269 @@
/**
* Public API functions
*/
+status_t encodeBufferDescriptorInfo(const BufferDescriptorInfo& bufferDescriptorInfo,
+ hidl_vec<uint8_t>* outBufferDescriptorInfo) {
+ return encode(bufferDescriptorInfo, outBufferDescriptorInfo, encodeBufferDescriptorInfoHelper);
+}
+
+status_t decodeBufferDescriptorInfo(const hidl_vec<uint8_t>& bufferDescriptorInfo,
+ BufferDescriptorInfo* outBufferDescriptorInfo) {
+ return decode(bufferDescriptorInfo, outBufferDescriptorInfo, decodeBufferDescriptorInfoHelper);
+}
status_t encodeBufferId(uint64_t bufferId, hidl_vec<uint8_t>* outBufferId) {
- return encode(MetadataType_BufferId, bufferId, outBufferId, encodeInteger);
+ return encodeMetadata(MetadataType_BufferId, bufferId, outBufferId, encodeInteger);
}
status_t decodeBufferId(const hidl_vec<uint8_t>& bufferId, uint64_t* outBufferId) {
- return decode(MetadataType_BufferId, bufferId, outBufferId, decodeInteger);
+ return decodeMetadata(MetadataType_BufferId, bufferId, outBufferId, decodeInteger);
}
status_t encodeName(const std::string& name, hidl_vec<uint8_t>* outName) {
- return encode(MetadataType_Name, name, outName, encodeString);
+ return encodeMetadata(MetadataType_Name, name, outName, encodeString);
}
status_t decodeName(const hidl_vec<uint8_t>& name, std::string* outName) {
- return decode(MetadataType_Name, name, outName, decodeString);
+ return decodeMetadata(MetadataType_Name, name, outName, decodeString);
}
status_t encodeWidth(uint64_t width, hidl_vec<uint8_t>* outWidth) {
- return encode(MetadataType_Width, width, outWidth, encodeInteger);
+ return encodeMetadata(MetadataType_Width, width, outWidth, encodeInteger);
}
status_t decodeWidth(const hidl_vec<uint8_t>& width, uint64_t* outWidth) {
- return decode(MetadataType_Width, width, outWidth, decodeInteger);
+ return decodeMetadata(MetadataType_Width, width, outWidth, decodeInteger);
}
status_t encodeHeight(uint64_t height, hidl_vec<uint8_t>* outHeight) {
- return encode(MetadataType_Height, height, outHeight, encodeInteger);
+ return encodeMetadata(MetadataType_Height, height, outHeight, encodeInteger);
}
status_t decodeHeight(const hidl_vec<uint8_t>& height, uint64_t* outHeight) {
- return decode(MetadataType_Height, height, outHeight, decodeInteger);
+ return decodeMetadata(MetadataType_Height, height, outHeight, decodeInteger);
}
status_t encodeLayerCount(uint64_t layerCount, hidl_vec<uint8_t>* outLayerCount) {
- return encode(MetadataType_LayerCount, layerCount, outLayerCount, encodeInteger);
+ return encodeMetadata(MetadataType_LayerCount, layerCount, outLayerCount, encodeInteger);
}
status_t decodeLayerCount(const hidl_vec<uint8_t>& layerCount, uint64_t* outLayerCount) {
- return decode(MetadataType_LayerCount, layerCount, outLayerCount, decodeInteger);
+ return decodeMetadata(MetadataType_LayerCount, layerCount, outLayerCount, decodeInteger);
}
status_t encodePixelFormatRequested(const hardware::graphics::common::V1_2::PixelFormat& pixelFormatRequested,
hidl_vec<uint8_t>* outPixelFormatRequested) {
- return encode(MetadataType_PixelFormatRequested, static_cast<int32_t>(pixelFormatRequested),
+ return encodeMetadata(MetadataType_PixelFormatRequested, static_cast<int32_t>(pixelFormatRequested),
outPixelFormatRequested, encodeInteger);
}
status_t decodePixelFormatRequested(const hidl_vec<uint8_t>& pixelFormatRequested,
hardware::graphics::common::V1_2::PixelFormat* outPixelFormatRequested) {
- return decode(MetadataType_PixelFormatRequested, pixelFormatRequested,
+ return decodeMetadata(MetadataType_PixelFormatRequested, pixelFormatRequested,
reinterpret_cast<int32_t*>(outPixelFormatRequested), decodeInteger);
}
status_t encodePixelFormatFourCC(uint32_t pixelFormatFourCC, hidl_vec<uint8_t>* outPixelFormatFourCC) {
- return encode(MetadataType_PixelFormatFourCC, pixelFormatFourCC, outPixelFormatFourCC,
+ return encodeMetadata(MetadataType_PixelFormatFourCC, pixelFormatFourCC, outPixelFormatFourCC,
encodeInteger);
}
status_t decodePixelFormatFourCC(const hidl_vec<uint8_t>& pixelFormatFourCC, uint32_t* outPixelFormatFourCC) {
- return decode(MetadataType_PixelFormatFourCC, pixelFormatFourCC, outPixelFormatFourCC,
+ return decodeMetadata(MetadataType_PixelFormatFourCC, pixelFormatFourCC, outPixelFormatFourCC,
decodeInteger);
}
status_t encodePixelFormatModifier(uint64_t pixelFormatModifier, hidl_vec<uint8_t>* outPixelFormatModifier) {
- return encode(MetadataType_PixelFormatModifier, pixelFormatModifier, outPixelFormatModifier,
+ return encodeMetadata(MetadataType_PixelFormatModifier, pixelFormatModifier, outPixelFormatModifier,
encodeInteger);
}
status_t decodePixelFormatModifier(const hidl_vec<uint8_t>& pixelFormatModifier, uint64_t* outPixelFormatModifier) {
- return decode(MetadataType_PixelFormatModifier, pixelFormatModifier, outPixelFormatModifier,
+ return decodeMetadata(MetadataType_PixelFormatModifier, pixelFormatModifier, outPixelFormatModifier,
decodeInteger);
}
status_t encodeUsage(uint64_t usage, hidl_vec<uint8_t>* outUsage) {
- return encode(MetadataType_Usage, usage, outUsage, encodeInteger);
+ return encodeMetadata(MetadataType_Usage, usage, outUsage, encodeInteger);
}
status_t decodeUsage(const hidl_vec<uint8_t>& usage, uint64_t* outUsage) {
- return decode(MetadataType_Usage, usage, outUsage, decodeInteger);
+ return decodeMetadata(MetadataType_Usage, usage, outUsage, decodeInteger);
}
status_t encodeAllocationSize(uint64_t allocationSize, hidl_vec<uint8_t>* outAllocationSize) {
- return encode(MetadataType_AllocationSize, allocationSize, outAllocationSize, encodeInteger);
+ return encodeMetadata(MetadataType_AllocationSize, allocationSize, outAllocationSize, encodeInteger);
}
status_t decodeAllocationSize(const hidl_vec<uint8_t>& allocationSize, uint64_t* outAllocationSize) {
- return decode(MetadataType_AllocationSize, allocationSize, outAllocationSize, decodeInteger);
+ return decodeMetadata(MetadataType_AllocationSize, allocationSize, outAllocationSize, decodeInteger);
}
status_t encodeProtectedContent(uint64_t protectedContent, hidl_vec<uint8_t>* outProtectedContent) {
- return encode(MetadataType_ProtectedContent, protectedContent, outProtectedContent,
+ return encodeMetadata(MetadataType_ProtectedContent, protectedContent, outProtectedContent,
encodeInteger);
}
status_t decodeProtectedContent(const hidl_vec<uint8_t>& protectedContent, uint64_t* outProtectedContent) {
- return decode(MetadataType_ProtectedContent, protectedContent, outProtectedContent,
+ return decodeMetadata(MetadataType_ProtectedContent, protectedContent, outProtectedContent,
decodeInteger);
}
status_t encodeCompression(const ExtendableType& compression, hidl_vec<uint8_t>* outCompression) {
- return encode(MetadataType_Compression, compression, outCompression, encodeExtendableType);
+ return encodeMetadata(MetadataType_Compression, compression, outCompression, encodeExtendableType);
}
status_t decodeCompression(const hidl_vec<uint8_t>& compression, ExtendableType* outCompression) {
- return decode(MetadataType_Compression, compression, outCompression, decodeExtendableType,
+ return decodeMetadata(MetadataType_Compression, compression, outCompression, decodeExtendableType,
clearExtendableType);
}
status_t encodeInterlaced(const ExtendableType& interlaced, hidl_vec<uint8_t>* outInterlaced) {
- return encode(MetadataType_Interlaced, interlaced, outInterlaced, encodeExtendableType);
+ return encodeMetadata(MetadataType_Interlaced, interlaced, outInterlaced, encodeExtendableType);
}
status_t decodeInterlaced(const hidl_vec<uint8_t>& interlaced, ExtendableType* outInterlaced) {
- return decode(MetadataType_Interlaced, interlaced, outInterlaced, decodeExtendableType,
+ return decodeMetadata(MetadataType_Interlaced, interlaced, outInterlaced, decodeExtendableType,
clearExtendableType);
}
status_t encodeChromaSiting(const ExtendableType& chromaSiting, hidl_vec<uint8_t>* outChromaSiting) {
- return encode(MetadataType_ChromaSiting, chromaSiting, outChromaSiting, encodeExtendableType);
+ return encodeMetadata(MetadataType_ChromaSiting, chromaSiting, outChromaSiting, encodeExtendableType);
}
status_t decodeChromaSiting(const hidl_vec<uint8_t>& chromaSiting, ExtendableType* outChromaSiting) {
- return decode(MetadataType_ChromaSiting, chromaSiting, outChromaSiting, decodeExtendableType,
+ return decodeMetadata(MetadataType_ChromaSiting, chromaSiting, outChromaSiting, decodeExtendableType,
clearExtendableType);
}
status_t encodePlaneLayouts(const std::vector<PlaneLayout>& planeLayouts, hidl_vec<uint8_t>* outPlaneLayouts) {
- return encode(MetadataType_PlaneLayouts, planeLayouts, outPlaneLayouts,
+ return encodeMetadata(MetadataType_PlaneLayouts, planeLayouts, outPlaneLayouts,
encodePlaneLayoutsHelper);
}
status_t decodePlaneLayouts(const hidl_vec<uint8_t>& planeLayouts, std::vector<PlaneLayout>* outPlaneLayouts) {
- return decode(MetadataType_PlaneLayouts, planeLayouts, outPlaneLayouts,
+ return decodeMetadata(MetadataType_PlaneLayouts, planeLayouts, outPlaneLayouts,
decodePlaneLayoutsHelper, clearPlaneLayouts);
}
status_t encodeDataspace(const Dataspace& dataspace, hidl_vec<uint8_t>* outDataspace) {
- return encode(MetadataType_Dataspace, static_cast<int32_t>(dataspace), outDataspace,
+ return encodeMetadata(MetadataType_Dataspace, static_cast<int32_t>(dataspace), outDataspace,
encodeInteger);
}
status_t decodeDataspace(const hidl_vec<uint8_t>& dataspace, Dataspace* outDataspace) {
- return decode(MetadataType_Dataspace, dataspace, reinterpret_cast<int32_t*>(outDataspace),
+ return decodeMetadata(MetadataType_Dataspace, dataspace, reinterpret_cast<int32_t*>(outDataspace),
decodeInteger);
}
status_t encodeBlendMode(const BlendMode& blendMode, hidl_vec<uint8_t>* outBlendMode) {
- return encode(MetadataType_BlendMode, static_cast<int32_t>(blendMode), outBlendMode,
+ return encodeMetadata(MetadataType_BlendMode, static_cast<int32_t>(blendMode), outBlendMode,
encodeInteger);
}
status_t decodeBlendMode(const hidl_vec<uint8_t>& blendMode, BlendMode* outBlendMode) {
- return decode(MetadataType_BlendMode, blendMode, reinterpret_cast<int32_t*>(outBlendMode),
+ return decodeMetadata(MetadataType_BlendMode, blendMode, reinterpret_cast<int32_t*>(outBlendMode),
decodeInteger);
}
status_t encodeSmpte2086(const std::optional<Smpte2086>& smpte2086,
hidl_vec<uint8_t>* outSmpte2086) {
- return encodeOptional(MetadataType_Smpte2086, smpte2086, outSmpte2086, encodeSmpte2086Helper);
+ return encodeOptionalMetadata(MetadataType_Smpte2086, smpte2086, outSmpte2086, encodeSmpte2086Helper);
}
status_t decodeSmpte2086(const hidl_vec<uint8_t>& smpte2086,
std::optional<Smpte2086>* outSmpte2086) {
- return decodeOptional(MetadataType_Smpte2086, smpte2086, outSmpte2086, decodeSmpte2086Helper);
+ return decodeOptionalMetadata(MetadataType_Smpte2086, smpte2086, outSmpte2086, decodeSmpte2086Helper);
}
status_t encodeCta861_3(const std::optional<Cta861_3>& cta861_3, hidl_vec<uint8_t>* outCta861_3) {
- return encodeOptional(MetadataType_Cta861_3, cta861_3, outCta861_3, encodeCta861_3Helper);
+ return encodeOptionalMetadata(MetadataType_Cta861_3, cta861_3, outCta861_3, encodeCta861_3Helper);
}
status_t decodeCta861_3(const hidl_vec<uint8_t>& cta861_3, std::optional<Cta861_3>* outCta861_3) {
- return decodeOptional(MetadataType_Cta861_3, cta861_3, outCta861_3, decodeCta861_3Helper);
+ return decodeOptionalMetadata(MetadataType_Cta861_3, cta861_3, outCta861_3, decodeCta861_3Helper);
}
status_t encodeSmpte2094_40(const std::optional<std::vector<uint8_t>>& smpte2094_40,
hidl_vec<uint8_t>* outSmpte2094_40) {
- return encodeOptional(MetadataType_Smpte2094_40, smpte2094_40, outSmpte2094_40,
+ return encodeOptionalMetadata(MetadataType_Smpte2094_40, smpte2094_40, outSmpte2094_40,
encodeByteVector);
}
status_t decodeSmpte2094_40(const hidl_vec<uint8_t>& smpte2094_40,
std::optional<std::vector<uint8_t>>* outSmpte2094_40) {
- return decodeOptional(MetadataType_Smpte2094_40, smpte2094_40, outSmpte2094_40,
+ return decodeOptionalMetadata(MetadataType_Smpte2094_40, smpte2094_40, outSmpte2094_40,
decodeByteVector);
}
status_t encodeUint32(const MetadataType& metadataType, uint32_t input,
hidl_vec<uint8_t>* output) {
- return encode(metadataType, input, output, encodeInteger);
+ return encodeMetadata(metadataType, input, output, encodeInteger);
}
status_t decodeUint32(const MetadataType& metadataType, const hidl_vec<uint8_t>& input,
uint32_t* output) {
- return decode(metadataType, input, output, decodeInteger);
+ return decodeMetadata(metadataType, input, output, decodeInteger);
}
status_t encodeInt32(const MetadataType& metadataType, int32_t input,
hidl_vec<uint8_t>* output) {
- return encode(metadataType, input, output, encodeInteger);
+ return encodeMetadata(metadataType, input, output, encodeInteger);
}
status_t decodeInt32(const MetadataType& metadataType, const hidl_vec<uint8_t>& input,
int32_t* output) {
- return decode(metadataType, input, output, decodeInteger);
+ return decodeMetadata(metadataType, input, output, decodeInteger);
}
status_t encodeUint64(const MetadataType& metadataType, uint64_t input,
hidl_vec<uint8_t>* output) {
- return encode(metadataType, input, output, encodeInteger);
+ return encodeMetadata(metadataType, input, output, encodeInteger);
}
status_t decodeUint64(const MetadataType& metadataType, const hidl_vec<uint8_t>& input,
uint64_t* output) {
- return decode(metadataType, input, output, decodeInteger);
+ return decodeMetadata(metadataType, input, output, decodeInteger);
}
status_t encodeInt64(const MetadataType& metadataType, int64_t input,
hidl_vec<uint8_t>* output) {
- return encode(metadataType, input, output, encodeInteger);
+ return encodeMetadata(metadataType, input, output, encodeInteger);
}
status_t decodeInt64(const MetadataType& metadataType, const hidl_vec<uint8_t>& input,
int64_t* output) {
- return decode(metadataType, input, output, decodeInteger);
+ return decodeMetadata(metadataType, input, output, decodeInteger);
}
status_t encodeFloat(const MetadataType& metadataType, float input,
hidl_vec<uint8_t>* output) {
- return encode(metadataType, input, output, encodeInteger);
+ return encodeMetadata(metadataType, input, output, encodeInteger);
}
status_t decodeFloat(const MetadataType& metadataType, const hidl_vec<uint8_t>& input,
float* output) {
- return decode(metadataType, input, output, decodeInteger);
+ return decodeMetadata(metadataType, input, output, decodeInteger);
}
status_t encodeDouble(const MetadataType& metadataType, double input,
hidl_vec<uint8_t>* output) {
- return encode(metadataType, input, output, encodeInteger);
+ return encodeMetadata(metadataType, input, output, encodeInteger);
}
status_t decodeDouble(const MetadataType& metadataType, const hidl_vec<uint8_t>& input,
double* output) {
- return decode(metadataType, input, output, decodeInteger);
+ return decodeMetadata(metadataType, input, output, decodeInteger);
}
status_t encodeString(const MetadataType& metadataType, const std::string& input,
hidl_vec<uint8_t>* output) {
- return encode(metadataType, input, output, encodeString);
+ return encodeMetadata(metadataType, input, output, encodeString);
}
status_t decodeString(const MetadataType& metadataType, const hidl_vec<uint8_t>& input,
std::string* output) {
- return decode(metadataType, input, output, decodeString);
+ return decodeMetadata(metadataType, input, output, decodeString);
}
bool isStandardMetadataType(const MetadataType& metadataType) {
diff --git a/libs/gralloc/types/fuzzer/gralloctypes.cpp b/libs/gralloc/types/fuzzer/gralloctypes.cpp
index b18f407..b5644be 100644
--- a/libs/gralloc/types/fuzzer/gralloctypes.cpp
+++ b/libs/gralloc/types/fuzzer/gralloctypes.cpp
@@ -31,6 +31,7 @@
using ::android::status_t;
using MetadataType = android::hardware::graphics::mapper::V4_0::IMapper::MetadataType;
+using BufferDescriptorInfo = android::hardware::graphics::mapper::V4_0::IMapper::BufferDescriptorInfo;
#define GRALLOCTYPES_DECODE(T, FUNC) \
[] (const ::android::hardware::hidl_vec<uint8_t>& vec) {\
@@ -53,6 +54,7 @@
// clang-format off
std::vector<GrallocTypesDecode> GRALLOCTYPES_DECODE_FUNCTIONS {
+ GRALLOCTYPES_DECODE(BufferDescriptorInfo, ::android::gralloc4::decodeBufferDescriptorInfo),
GRALLOCTYPES_DECODE(uint64_t, ::android::gralloc4::decodeBufferId),
GRALLOCTYPES_DECODE(std::string, ::android::gralloc4::decodeName),
GRALLOCTYPES_DECODE(uint64_t, ::android::gralloc4::decodeWidth),
diff --git a/libs/gralloc/types/include/gralloctypes/Gralloc4.h b/libs/gralloc/types/include/gralloctypes/Gralloc4.h
index ca0d4b5..d855439 100644
--- a/libs/gralloc/types/include/gralloctypes/Gralloc4.h
+++ b/libs/gralloc/types/include/gralloctypes/Gralloc4.h
@@ -30,6 +30,8 @@
#include <aidl/android/hardware/graphics/common/XyColor.h>
#include <android/hardware/graphics/mapper/4.0/IMapper.h>
+namespace android {
+
/**
* Define equality operators for Stable AIDL types.
*/
@@ -210,8 +212,6 @@
return !(lhs == rhs);
}
-namespace android {
-
namespace gralloc4 {
#define GRALLOC4_STANDARD_METADATA_TYPE "android.hardware.graphics.common.StandardMetadataType"
@@ -414,6 +414,12 @@
/*---------------------------------------------------------------------------------------------*/
/**
+ * The functions below encode and decode BufferDescriptorInfo into a byte stream.
+ */
+status_t encodeBufferDescriptorInfo(const android::hardware::graphics::mapper::V4_0::IMapper::BufferDescriptorInfo& bufferDescriptorInfo, android::hardware::hidl_vec<uint8_t>* outBufferDescriptorInfo);
+status_t decodeBufferDescriptorInfo(const android::hardware::hidl_vec<uint8_t>& bufferDescriptorInfo, android::hardware::graphics::mapper::V4_0::IMapper::BufferDescriptorInfo* outBufferDescriptorInfo);
+
+/**
* The functions below encode and decode standard metadata into a byte stream. It is STRONGLY
* recommended that both the vendor and system partitions use these functions when getting
* and setting metadata through gralloc 4 (IMapper 4.0).
diff --git a/libs/gralloc/types/tests/Gralloc4_test.cpp b/libs/gralloc/types/tests/Gralloc4_test.cpp
index 3542ed9..dbe41f1 100644
--- a/libs/gralloc/types/tests/Gralloc4_test.cpp
+++ b/libs/gralloc/types/tests/Gralloc4_test.cpp
@@ -25,6 +25,7 @@
using android::hardware::hidl_vec;
using android::hardware::graphics::common::V1_2::PixelFormat;
+using android::hardware::graphics::common::V1_2::BufferUsage;
using aidl::android::hardware::graphics::common::BlendMode;
using aidl::android::hardware::graphics::common::ChromaSiting;
@@ -41,6 +42,7 @@
using aidl::android::hardware::graphics::common::StandardMetadataType;
using aidl::android::hardware::graphics::common::XyColor;
+using BufferDescriptorInfo = android::hardware::graphics::mapper::V4_0::IMapper::BufferDescriptorInfo;
using MetadataType = android::hardware::graphics::mapper::V4_0::IMapper::MetadataType;
namespace android {
@@ -435,6 +437,19 @@
ASSERT_NO_FATAL_FAILURE(testHelperStableAidlTypeOptional(GetParam(), gralloc4::encodeSmpte2094_40, gralloc4::decodeSmpte2094_40));
}
+class Gralloc4TestBufferDescriptorInfo : public testing::TestWithParam<BufferDescriptorInfo> { };
+
+INSTANTIATE_TEST_CASE_P(
+ Gralloc4TestBufferDescriptorInfoParams, Gralloc4TestBufferDescriptorInfo,
+ ::testing::Values(BufferDescriptorInfo{"BufferName", 64, 64, 1,
+ PixelFormat::RGBA_8888,
+ static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN),
+ 1024}));
+
+TEST_P(Gralloc4TestBufferDescriptorInfo, BufferDescriptorInfo) {
+ ASSERT_NO_FATAL_FAILURE(testHelperConst(GetParam(), gralloc4::encodeBufferDescriptorInfo, gralloc4::decodeBufferDescriptorInfo));
+}
+
class Gralloc4TestErrors : public testing::Test { };
TEST_F(Gralloc4TestErrors, Gralloc4TestEncodeNull) {
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 5959340..55a892e 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -69,9 +69,6 @@
"SurfaceComposerClient.cpp",
"SyncFeatures.cpp",
"view/Surface.cpp",
- "surfacetexture/SurfaceTexture.cpp",
- "surfacetexture/ImageConsumer.cpp",
- "surfacetexture/EGLConsumer.cpp",
],
shared_libs: [
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index f88ddf1..d2b25a2 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -48,7 +48,7 @@
mBufferItemConsumer->setBufferFreedListener(this);
mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight);
mBufferItemConsumer->setDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888);
- mBufferItemConsumer->setTransformHint(mSurfaceControl->getTransformHint());
+ mTransformHint = mSurfaceControl->getTransformHint();
mNumAcquired = 0;
mNumFrameAvailable = 0;
@@ -62,7 +62,6 @@
mWidth = width;
mHeight = height;
mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight);
- mBufferItemConsumer->setTransformHint(mSurfaceControl->getTransformHint());
}
static void transactionCallbackThunk(void* context, nsecs_t latchTime,
@@ -109,7 +108,7 @@
void BLASTBufferQueue::processNextBufferLocked() {
ATRACE_CALL();
- if (mNumFrameAvailable == 0) {
+ if (mNumFrameAvailable == 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS) {
return;
}
@@ -155,6 +154,7 @@
t->setFrame(mSurfaceControl, {0, 0, (int32_t)buffer->getWidth(), (int32_t)buffer->getHeight()});
t->setCrop(mSurfaceControl, computeCrop(bufferItem));
t->setTransform(mSurfaceControl, bufferItem.mTransform);
+ t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse);
if (applyTransaction) {
t->apply();
diff --git a/libs/gui/BufferHubConsumer.cpp b/libs/gui/BufferHubConsumer.cpp
index b5cdeb2..0ddb87e 100644
--- a/libs/gui/BufferHubConsumer.cpp
+++ b/libs/gui/BufferHubConsumer.cpp
@@ -147,6 +147,16 @@
return INVALID_OPERATION;
}
+status_t BufferHubConsumer::setFrameRate(float /*frameRate*/) {
+ ALOGE("BufferHubConsumer::setFrameRate: not implemented.");
+ return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::getFrameRate(float* /*frameRate*/) const {
+ ALOGE("BufferHubConsumer::getFrameRate: not implemented.");
+ return INVALID_OPERATION;
+}
+
status_t BufferHubConsumer::dumpState(const String8& /*prefix*/, String8* /*outResult*/) const {
ALOGE("BufferHubConsumer::dumpState: not implemented.");
return INVALID_OPERATION;
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 6418e8c..9b74fef 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -775,6 +775,18 @@
return NO_ERROR;
}
+status_t BufferQueueConsumer::setFrameRate(float frameRate) {
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
+ mCore->mFrameRate = frameRate;
+ return NO_ERROR;
+}
+
+status_t BufferQueueConsumer::getFrameRate(float* frameRate) const {
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
+ *frameRate = mCore->mFrameRate;
+ return NO_ERROR;
+}
+
status_t BufferQueueConsumer::dumpState(const String8& prefix, String8* outResult) const {
struct passwd* pwd = getpwnam("shell");
uid_t shellUid = pwd ? pwd->pw_uid : 0;
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index e6df757..6b11a54 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -1670,4 +1670,14 @@
return NO_ERROR;
}
+status_t BufferQueueProducer::setFrameRate(float frameRate) {
+ ATRACE_CALL();
+ BQ_LOGV("setFrameRate: %.0f", frameRate);
+
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
+
+ mCore->mFrameRate = frameRate;
+ return NO_ERROR;
+}
+
} // namespace android
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 9f91d9d..515f45c 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -363,6 +363,24 @@
return OK;
}
+status_t ConsumerBase::setFrameRate(float frameRate) {
+ Mutex::Autolock _l(mMutex);
+ if (mAbandoned) {
+ CB_LOGE("setFrameRate: ConsumerBase is abandoned!");
+ return NO_INIT;
+ }
+ return mConsumer->setFrameRate(frameRate);
+}
+
+status_t ConsumerBase::getFrameRate(float* frameRate) {
+ Mutex::Autolock _l(mMutex);
+ if (mAbandoned) {
+ CB_LOGE("getFrameRate: ConsumerBase is abandoned!");
+ return NO_INIT;
+ }
+ return mConsumer->getFrameRate(frameRate);
+}
+
void ConsumerBase::dumpState(String8& result) const {
dumpState(result, "");
}
diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp
index c705d39..2521a7c 100644
--- a/libs/gui/IGraphicBufferConsumer.cpp
+++ b/libs/gui/IGraphicBufferConsumer.cpp
@@ -51,6 +51,8 @@
GET_SIDEBAND_STREAM,
GET_OCCUPANCY_HISTORY,
DISCARD_FREE_BUFFERS,
+ SET_FRAME_RATE,
+ GET_FRAME_RATE,
DUMP_STATE,
LAST = DUMP_STATE,
};
@@ -163,6 +165,16 @@
Tag::DISCARD_FREE_BUFFERS);
}
+ status_t setFrameRate(float frameRate) override {
+ using Signature = decltype(&IGraphicBufferConsumer::setFrameRate);
+ return callRemote<Signature>(Tag::SET_FRAME_RATE, frameRate);
+ }
+
+ status_t getFrameRate(float* frameRate) const override {
+ using Signature = decltype(&IGraphicBufferConsumer::getFrameRate);
+ return callRemote<Signature>(Tag::GET_FRAME_RATE, frameRate);
+ }
+
status_t dumpState(const String8& prefix, String8* outResult) const override {
using Signature = status_t (IGraphicBufferConsumer::*)(const String8&, String8*) const;
return callRemote<Signature>(Tag::DUMP_STATE, prefix, outResult);
@@ -220,6 +232,10 @@
return callLocal(data, reply, &IGraphicBufferConsumer::getOccupancyHistory);
case Tag::DISCARD_FREE_BUFFERS:
return callLocal(data, reply, &IGraphicBufferConsumer::discardFreeBuffers);
+ case Tag::SET_FRAME_RATE:
+ return callLocal(data, reply, &IGraphicBufferConsumer::setFrameRate);
+ case Tag::GET_FRAME_RATE:
+ return callLocal(data, reply, &IGraphicBufferConsumer::getFrameRate);
case Tag::DUMP_STATE: {
using Signature = status_t (IGraphicBufferConsumer::*)(const String8&, String8*) const;
return callLocal<Signature>(data, reply, &IGraphicBufferConsumer::dumpState);
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 0009a57..75876f2 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -74,6 +74,7 @@
GET_CONSUMER_USAGE,
SET_LEGACY_BUFFER_DROP,
SET_AUTO_PREROTATION,
+ SET_FRAME_RATE,
};
class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@@ -559,6 +560,14 @@
}
return result;
}
+
+ virtual status_t setFrameRate(float frameRate) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
+ data.writeFloat(frameRate);
+ status_t result = remote()->transact(SET_FRAME_RATE, data, &reply, IBinder::FLAG_ONEWAY);
+ return result;
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -691,6 +700,8 @@
status_t setAutoPrerotation(bool autoPrerotation) override {
return mBase->setAutoPrerotation(autoPrerotation);
}
+
+ status_t setFrameRate(float frameRate) override { return mBase->setFrameRate(frameRate); }
};
IMPLEMENT_HYBRID_META_INTERFACE(GraphicBufferProducer,
@@ -710,6 +721,12 @@
return INVALID_OPERATION;
}
+status_t IGraphicBufferProducer::setFrameRate(float frameRate) {
+ // No-op for IGBP other than BufferQueue.
+ (void)frameRate;
+ return INVALID_OPERATION;
+}
+
status_t IGraphicBufferProducer::exportToParcel(Parcel* parcel) {
status_t res = OK;
res = parcel->writeUint32(USE_BUFFER_QUEUE);
@@ -1079,6 +1096,13 @@
reply->writeInt32(result);
return NO_ERROR;
}
+ case SET_FRAME_RATE: {
+ CHECK_INTERFACE(IGraphicBuffer, data, reply);
+ float frameRate = data.readFloat();
+ status_t result = setFrameRate(frameRate);
+ reply->writeInt32(result);
+ return NO_ERROR;
+ }
}
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index d34fe3b..073543c 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -397,32 +397,6 @@
return reply.readInt32();
}
- virtual status_t setActiveConfig(const sp<IBinder>& display, int id)
- {
- Parcel data, reply;
- status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (result != NO_ERROR) {
- ALOGE("setActiveConfig failed to writeInterfaceToken: %d", result);
- return result;
- }
- result = data.writeStrongBinder(display);
- if (result != NO_ERROR) {
- ALOGE("setActiveConfig failed to writeStrongBinder: %d", result);
- return result;
- }
- result = data.writeInt32(id);
- if (result != NO_ERROR) {
- ALOGE("setActiveConfig failed to writeInt32: %d", result);
- return result;
- }
- result = remote()->transact(BnSurfaceComposer::SET_ACTIVE_CONFIG, data, &reply);
- if (result != NO_ERROR) {
- ALOGE("setActiveConfig failed to transact: %d", result);
- return result;
- }
- return reply.readInt32();
- }
-
virtual status_t getDisplayColorModes(const sp<IBinder>& display,
Vector<ColorMode>* outColorModes) {
Parcel data, reply;
@@ -1357,14 +1331,6 @@
reply->writeInt32(id);
return NO_ERROR;
}
- case SET_ACTIVE_CONFIG: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> display = data.readStrongBinder();
- int id = data.readInt32();
- status_t result = setActiveConfig(display, id);
- reply->writeInt32(result);
- return NO_ERROR;
- }
case GET_DISPLAY_COLOR_MODES: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
Vector<ColorMode> colorModes;
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index a7c4f46..5547efc 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -86,6 +86,7 @@
memcpy(output.writeInplace(16 * sizeof(float)),
colorTransform.asArray(), 16 * sizeof(float));
output.writeFloat(cornerRadius);
+ output.writeUint32(backgroundBlurRadius);
output.writeStrongBinder(cachedBuffer.token.promote());
output.writeUint64(cachedBuffer.id);
output.writeParcelable(metadata);
@@ -110,6 +111,8 @@
}
}
output.writeFloat(shadowRadius);
+ output.writeInt32(frameRateSelectionPriority);
+ output.writeFloat(frameRate);
return NO_ERROR;
}
@@ -171,6 +174,7 @@
colorTransform = mat4(static_cast<const float*>(input.readInplace(16 * sizeof(float))));
cornerRadius = input.readFloat();
+ backgroundBlurRadius = input.readUint32();
cachedBuffer.token = input.readStrongBinder();
cachedBuffer.id = input.readUint64();
input.readParcelable(&metadata);
@@ -188,6 +192,8 @@
listeners.emplace_back(listener, callbackIds);
}
shadowRadius = input.readFloat();
+ frameRateSelectionPriority = input.readInt32();
+ frameRate = input.readFloat();
return NO_ERROR;
}
@@ -303,6 +309,10 @@
what |= eCornerRadiusChanged;
cornerRadius = other.cornerRadius;
}
+ if (other.what & eBackgroundBlurRadiusChanged) {
+ what |= eBackgroundBlurRadiusChanged;
+ backgroundBlurRadius = other.backgroundBlurRadius;
+ }
if (other.what & eDeferTransaction_legacy) {
what |= eDeferTransaction_legacy;
barrierHandle_legacy = other.barrierHandle_legacy;
@@ -406,12 +416,18 @@
what |= eMetadataChanged;
metadata.merge(other.metadata);
}
-
if (other.what & eShadowRadiusChanged) {
what |= eShadowRadiusChanged;
shadowRadius = other.shadowRadius;
}
-
+ if (other.what & eFrameRateSelectionPriority) {
+ what |= eFrameRateSelectionPriority;
+ frameRateSelectionPriority = other.frameRateSelectionPriority;
+ }
+ if (other.what & eFrameRateChanged) {
+ what |= eFrameRateChanged;
+ frameRate = other.frameRate;
+ }
if ((other.what & what) != other.what) {
ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
"other.what=0x%" PRIu64 " what=0x%" PRIu64,
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/gui/Surface.cpp b/libs/gui/Surface.cpp
index e490d6d..d5cf11d 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -1093,6 +1093,9 @@
case NATIVE_WINDOW_GET_LAST_QUEUE_DURATION:
res = dispatchGetLastQueueDuration(args);
break;
+ case NATIVE_WINDOW_SET_FRAME_RATE:
+ res = dispatchSetFrameRate(args);
+ break;
default:
res = NAME_NOT_FOUND;
break;
@@ -1321,6 +1324,11 @@
return NO_ERROR;
}
+int Surface::dispatchSetFrameRate(va_list args) {
+ float frameRate = static_cast<float>(va_arg(args, double));
+ return setFrameRate(frameRate);
+}
+
bool Surface::transformToDisplayInverse() {
return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) ==
NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
@@ -2064,4 +2072,11 @@
mSurfaceListener->onBuffersDiscarded(discardedBufs);
}
+status_t Surface::setFrameRate(float frameRate) {
+ ATRACE_CALL();
+ ALOGV("Surface::setTargetFrameRate");
+ Mutex::Autolock lock(mMutex);
+ return mGraphicBufferProducer->setFrameRate(frameRate);
+}
+
}; // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 5e259e2..63dc333 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -918,6 +918,18 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBackgroundBlurRadius(
+ const sp<SurfaceControl>& sc, int backgroundBlurRadius) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+ s->what |= layer_state_t::eBackgroundBlurRadiusChanged;
+ s->backgroundBlurRadius = backgroundBlurRadius;
+ return *this;
+}
+
SurfaceComposerClient::Transaction&
SurfaceComposerClient::Transaction::deferTransactionUntil_legacy(const sp<SurfaceControl>& sc,
const sp<IBinder>& handle,
@@ -1192,6 +1204,22 @@
}
SurfaceComposerClient::Transaction&
+SurfaceComposerClient::Transaction::setFrameRateSelectionPriority(const sp<SurfaceControl>& sc,
+ int32_t priority) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+
+ s->what |= layer_state_t::eFrameRateSelectionPriority;
+ s->frameRateSelectionPriority = priority;
+
+ registerSurfaceControlForCallback(sc);
+ return *this;
+}
+
+SurfaceComposerClient::Transaction&
SurfaceComposerClient::Transaction::addTransactionCompletedCallback(
TransactionCompletedCallbackTakesContext callback, void* callbackContext) {
auto listener = TransactionCompletedListener::getInstance();
@@ -1360,6 +1388,18 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameRate(
+ const sp<SurfaceControl>& sc, float frameRate) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+ s->what |= layer_state_t::eFrameRateChanged;
+ s->frameRate = frameRate;
+ return *this;
+}
+
// ---------------------------------------------------------------------------
DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) {
@@ -1611,10 +1651,6 @@
return ComposerService::getComposerService()->getActiveConfig(display);
}
-status_t SurfaceComposerClient::setActiveConfig(const sp<IBinder>& display, int id) {
- return ComposerService::getComposerService()->setActiveConfig(display, id);
-}
-
status_t SurfaceComposerClient::setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
int32_t defaultConfig,
float minRefreshRate,
diff --git a/libs/gui/include/gui/BufferHubConsumer.h b/libs/gui/include/gui/BufferHubConsumer.h
index d380770..d756203 100644
--- a/libs/gui/include/gui/BufferHubConsumer.h
+++ b/libs/gui/include/gui/BufferHubConsumer.h
@@ -93,6 +93,12 @@
// See |IGraphicBufferConsumer::discardFreeBuffers|
status_t discardFreeBuffers() override;
+ // See |IGraphicBufferConsumer::setFrameRate|
+ status_t setFrameRate(float frameRate) override;
+
+ // See |IGraphicBufferConsumer::getFrameRate|
+ status_t getFrameRate(float* frameRate) const override;
+
// See |IGraphicBufferConsumer::dumpState|
status_t dumpState(const String8& prefix, String8* outResult) const override;
diff --git a/libs/gui/include/gui/BufferQueueConsumer.h b/libs/gui/include/gui/BufferQueueConsumer.h
index 7db69ec..e9f0449 100644
--- a/libs/gui/include/gui/BufferQueueConsumer.h
+++ b/libs/gui/include/gui/BufferQueueConsumer.h
@@ -149,6 +149,12 @@
// See IGraphicBufferConsumer::discardFreeBuffers
virtual status_t discardFreeBuffers() override;
+ // See IGraphicBufferConsumer::setFrameRate.
+ virtual status_t setFrameRate(float frameRate) override;
+
+ // See IGraphicBufferConsumer::getFrameRate.
+ virtual status_t getFrameRate(float* frameRate) const override;
+
// dump our state in a String
status_t dumpState(const String8& prefix, String8* outResult) const override;
diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h
index 557c28b..05c2074 100644
--- a/libs/gui/include/gui/BufferQueueCore.h
+++ b/libs/gui/include/gui/BufferQueueCore.h
@@ -354,6 +354,9 @@
// mTransformHintInUse is to cache the mTransformHint used by the producer.
uint32_t mTransformHintInUse;
+ // The frame rate the app intends to run at.
+ float mFrameRate;
+
}; // class BufferQueueCore
} // namespace android
diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h
index 9ad92a6..2dec663 100644
--- a/libs/gui/include/gui/BufferQueueProducer.h
+++ b/libs/gui/include/gui/BufferQueueProducer.h
@@ -193,6 +193,9 @@
// See IGraphicBufferProducer::setAutoPrerotation
virtual status_t setAutoPrerotation(bool autoPrerotation);
+ // See IGraphicBufferProducer::setFrameRate
+ virtual status_t setFrameRate(float frameRate) override;
+
private:
// This is required by the IBinder::DeathRecipient interface
virtual void binderDied(const wp<IBinder>& who);
diff --git a/libs/gui/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h
index 8ff0cd0..cfed9aa 100644
--- a/libs/gui/include/gui/ConsumerBase.h
+++ b/libs/gui/include/gui/ConsumerBase.h
@@ -111,6 +111,12 @@
// See IGraphicBufferConsumer::discardFreeBuffers
status_t discardFreeBuffers();
+ // See IGraphicBufferConsumer::setFrameRate
+ status_t setFrameRate(float frameRate);
+
+ // See IGraphicBufferConsumer::getFrameRate
+ status_t getFrameRate(float* frameRate);
+
private:
ConsumerBase(const ConsumerBase&);
void operator=(const ConsumerBase&);
diff --git a/libs/gui/include/gui/IGraphicBufferConsumer.h b/libs/gui/include/gui/IGraphicBufferConsumer.h
index 9fb7580..54f77b4 100644
--- a/libs/gui/include/gui/IGraphicBufferConsumer.h
+++ b/libs/gui/include/gui/IGraphicBufferConsumer.h
@@ -271,6 +271,16 @@
// call to free up any of its locally cached buffers.
virtual status_t discardFreeBuffers() = 0;
+ // Set the frame rate the producer will run at.
+ //
+ // Return of a value other than NO_ERROR means an unknown error has occurred.
+ virtual status_t setFrameRate(float frameRate) = 0;
+
+ // Get the frame rate the producer will run at.
+ //
+ // Return of a value other than NO_ERROR means an unknown error has occurred.
+ virtual status_t getFrameRate(float* frameRate) const = 0;
+
// dump state into a string
virtual status_t dumpState(const String8& prefix, String8* outResult) const = 0;
diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h
index 25ce1ca..680d64e 100644
--- a/libs/gui/include/gui/IGraphicBufferProducer.h
+++ b/libs/gui/include/gui/IGraphicBufferProducer.h
@@ -637,6 +637,9 @@
// the width and height used for dequeueBuffer will be additionally swapped.
virtual status_t setAutoPrerotation(bool autoPrerotation);
+ // Sets the apps intended frame rate.
+ virtual status_t setFrameRate(float frameRate);
+
// Static method exports any IGraphicBufferProducer object to a parcel. It
// handles null producer as well.
static status_t exportToParcel(const sp<IGraphicBufferProducer>& producer,
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 9804c92..46c9f3a 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -176,10 +176,6 @@
* currently active */
virtual int getActiveConfig(const sp<IBinder>& display) = 0;
- /* specifies which configuration (of those returned by getDisplayInfo)
- * should be used */
- virtual status_t setActiveConfig(const sp<IBinder>& display, int id) = 0;
-
virtual status_t getDisplayColorModes(const sp<IBinder>& display,
Vector<ui::ColorMode>* outColorModes) = 0;
virtual status_t getDisplayNativePrimaries(const sp<IBinder>& display,
@@ -507,7 +503,6 @@
GET_SUPPORTED_FRAME_TIMESTAMPS,
GET_DISPLAY_CONFIGS,
GET_ACTIVE_CONFIG,
- SET_ACTIVE_CONFIG,
CONNECT_DISPLAY_UNUSED, // unused, fails permissions check
CAPTURE_SCREEN,
CAPTURE_LAYERS,
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index fb18639..c256a09 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -99,6 +99,9 @@
eBackgroundColorChanged = 0x4'00000000,
eMetadataChanged = 0x8'00000000,
eColorSpaceAgnosticChanged = 0x10'00000000,
+ eFrameRateSelectionPriority = 0x20'00000000,
+ eFrameRateChanged = 0x40'00000000,
+ eBackgroundBlurRadiusChanged = 0x80'00000000,
};
layer_state_t()
@@ -115,6 +118,7 @@
reserved(0),
crop_legacy(Rect::INVALID_RECT),
cornerRadius(0.0f),
+ backgroundBlurRadius(0),
frameNumber_legacy(0),
overrideScalingMode(-1),
transform(0),
@@ -128,7 +132,9 @@
bgColorAlpha(0),
bgColorDataspace(ui::Dataspace::UNKNOWN),
colorSpaceAgnostic(false),
- shadowRadius(0.0f) {
+ shadowRadius(0.0f),
+ frameRateSelectionPriority(-1),
+ frameRate(0.0f) {
matrix.dsdx = matrix.dtdy = 1.0f;
matrix.dsdy = matrix.dtdx = 0.0f;
hdrMetadata.validTypes = 0;
@@ -159,6 +165,7 @@
matrix22_t matrix;
Rect crop_legacy;
float cornerRadius;
+ uint32_t backgroundBlurRadius;
sp<IBinder> barrierHandle_legacy;
sp<IBinder> reparentHandle;
uint64_t frameNumber_legacy;
@@ -209,6 +216,11 @@
// Draws a shadow around the surface.
float shadowRadius;
+
+ // Priority of the layer assigned by Window Manager.
+ int32_t frameRateSelectionPriority;
+
+ float frameRate;
};
struct ComposerState {
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index e582509..86cc61f 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -179,6 +179,9 @@
status_t getUniqueId(uint64_t* outId) const;
status_t getConsumerUsage(uint64_t* outUsage) const;
+ // See IGraphicBufferProducer::setFrameRate
+ status_t setFrameRate(float frameRate);
+
protected:
virtual ~Surface();
@@ -248,6 +251,7 @@
int dispatchSetDequeueTimeout(va_list args);
int dispatchGetLastDequeueDuration(va_list args);
int dispatchGetLastQueueDuration(va_list args);
+ int dispatchSetFrameRate(va_list args);
bool transformToDisplayInverse();
protected:
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 44f29ea..08e6a5a 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -114,10 +114,6 @@
// returned by getDisplayInfo)
static int getActiveConfig(const sp<IBinder>& display);
- // Set a new active configuration using an index relative to the list
- // returned by getDisplayInfo
- static status_t setActiveConfig(const sp<IBinder>& display, int id);
-
// Sets the refresh rate boundaries for display configuration.
// For all other parameters, default configuration is used. The index for the default is
// corresponting to the configs returned from getDisplayConfigs().
@@ -435,6 +431,8 @@
float dsdx, float dtdx, float dtdy, float dsdy);
Transaction& setCrop_legacy(const sp<SurfaceControl>& sc, const Rect& crop);
Transaction& setCornerRadius(const sp<SurfaceControl>& sc, float cornerRadius);
+ Transaction& setBackgroundBlurRadius(const sp<SurfaceControl>& sc,
+ int backgroundBlurRadius);
Transaction& setLayerStack(const sp<SurfaceControl>& sc, uint32_t layerStack);
Transaction& setMetadata(const sp<SurfaceControl>& sc, uint32_t key, const Parcel& p);
// Defers applying any changes made in this transaction until the Layer
@@ -483,6 +481,9 @@
Transaction& setDesiredPresentTime(nsecs_t desiredPresentTime);
Transaction& setColorSpaceAgnostic(const sp<SurfaceControl>& sc, const bool agnostic);
+ // Sets information about the priority of the frame.
+ Transaction& setFrameRateSelectionPriority(const sp<SurfaceControl>& sc, int32_t priority);
+
Transaction& addTransactionCompletedCallback(
TransactionCompletedCallbackTakesContext callback, void* callbackContext);
@@ -517,6 +518,8 @@
const Rect& source, const Rect& dst, int transform);
Transaction& setShadowRadius(const sp<SurfaceControl>& sc, float cornerRadius);
+ Transaction& setFrameRate(const sp<SurfaceControl>& sc, float frameRate);
+
status_t setDisplaySurface(const sp<IBinder>& token,
const sp<IGraphicBufferProducer>& bufferProducer);
diff --git a/libs/gui/include/gui/mock/GraphicBufferConsumer.h b/libs/gui/include/gui/mock/GraphicBufferConsumer.h
index 98f24c2..e940cf3 100644
--- a/libs/gui/include/gui/mock/GraphicBufferConsumer.h
+++ b/libs/gui/include/gui/mock/GraphicBufferConsumer.h
@@ -49,6 +49,8 @@
MOCK_CONST_METHOD1(getSidebandStream, status_t(sp<NativeHandle>*));
MOCK_METHOD2(getOccupancyHistory, status_t(bool, std::vector<OccupancyTracker::Segment>*));
MOCK_METHOD0(discardFreeBuffers, status_t());
+ MOCK_METHOD1(setFrameRate, status_t(float));
+ MOCK_CONST_METHOD1(getFrameRate, status_t(float*));
MOCK_CONST_METHOD2(dumpState, status_t(const String8&, String8*));
};
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index f9540b2..25c032f 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -723,10 +723,6 @@
status_t getDisplayStats(const sp<IBinder>& /*display*/,
DisplayStatInfo* /*stats*/) override { return NO_ERROR; }
int getActiveConfig(const sp<IBinder>& /*display*/) override { return 0; }
- status_t setActiveConfig(const sp<IBinder>& /*display*/, int /*id*/)
- override {
- return NO_ERROR;
- }
status_t getDisplayColorModes(const sp<IBinder>& /*display*/,
Vector<ColorMode>* /*outColorModes*/) override {
return NO_ERROR;
diff --git a/libs/nativedisplay/Android.bp b/libs/nativedisplay/Android.bp
index bcc99fc..c956578 100644
--- a/libs/nativedisplay/Android.bp
+++ b/libs/nativedisplay/Android.bp
@@ -45,6 +45,10 @@
srcs: [
"AChoreographer.cpp",
"ADisplay.cpp",
+ "surfacetexture/surface_texture.cpp",
+ "surfacetexture/SurfaceTexture.cpp",
+ "surfacetexture/ImageConsumer.cpp",
+ "surfacetexture/EGLConsumer.cpp",
],
shared_libs: [
@@ -53,6 +57,10 @@
"libnativewindow",
"libui",
"libutils",
+ "libcutils",
+ "libEGL",
+ "libGLESv2",
+ "libnativehelper",
],
header_libs: [
diff --git a/libs/gui/include/gui/surfacetexture/EGLConsumer.h b/libs/nativedisplay/include/surfacetexture/EGLConsumer.h
similarity index 100%
rename from libs/gui/include/gui/surfacetexture/EGLConsumer.h
rename to libs/nativedisplay/include/surfacetexture/EGLConsumer.h
diff --git a/libs/gui/include/gui/surfacetexture/ImageConsumer.h b/libs/nativedisplay/include/surfacetexture/ImageConsumer.h
similarity index 100%
rename from libs/gui/include/gui/surfacetexture/ImageConsumer.h
rename to libs/nativedisplay/include/surfacetexture/ImageConsumer.h
diff --git a/libs/gui/include/gui/surfacetexture/SurfaceTexture.h b/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h
similarity index 100%
rename from libs/gui/include/gui/surfacetexture/SurfaceTexture.h
rename to libs/nativedisplay/include/surfacetexture/SurfaceTexture.h
diff --git a/libs/gui/include/gui/surfacetexture/surface_texture_platform.h b/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h
similarity index 85%
rename from libs/gui/include/gui/surfacetexture/surface_texture_platform.h
rename to libs/nativedisplay/include/surfacetexture/surface_texture_platform.h
index 72f98ad..6a94a77 100644
--- a/libs/gui/include/gui/surfacetexture/surface_texture_platform.h
+++ b/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h
@@ -22,17 +22,11 @@
#include <system/graphics.h>
-#include <gui/IGraphicBufferProducer.h>
-#include <gui/surfacetexture/SurfaceTexture.h>
-
// This file provides a facade API on top of SurfaceTexture, which avoids using
// C++ types. This is still a C++ unstable API though. Ideally features here
// will be exposed via public NDK API and this file will be deleted.
-struct ASurfaceTexture {
- android::sp<android::SurfaceTexture> consumer;
- android::sp<android::IGraphicBufferProducer> producer;
-};
+struct ASurfaceTexture;
namespace android {
@@ -79,13 +73,6 @@
ASurfaceTexture_fenceWait fenceWait,
void* fencePassThroughHandle);
-/**
- * ASurfaceTexture_create creates an ASurfaceTexture, which is
- * a simple struct containing a SurfaceTexture and an IGraphicBufferProducer.
- */
-ASurfaceTexture* ASurfaceTexture_create(sp<SurfaceTexture> consumer,
- sp<IGraphicBufferProducer> producer);
-
} // namespace android
#endif // _ANDROID_GRAPHICS_SURFACE_TEXTURE_PLATFORM_H
diff --git a/libs/nativedisplay/libnativedisplay.map.txt b/libs/nativedisplay/libnativedisplay.map.txt
index 650bdf1..483fb25 100644
--- a/libs/nativedisplay/libnativedisplay.map.txt
+++ b/libs/nativedisplay/libnativedisplay.map.txt
@@ -11,6 +11,8 @@
AChoreographer_destroy; # apex # introduced=30
AChoreographer_getFd; # apex # introduced=30
AChoreographer_handlePendingEvents; # apex # introduced=30
+ ASurfaceTexture_fromSurfaceTexture; # apex # introduced=30
+ ASurfaceTexture_release; # apex # introduced=30
local:
*;
};
@@ -30,5 +32,16 @@
android::ADisplayConfig_getFps*;
android::ADisplayConfig_getCompositorOffsetNanos*;
android::ADisplayConfig_getAppVsyncOffsetNanos*;
+ android::ASurfaceTexture_getCurrentTextureTarget*;
+ android::ASurfaceTexture_takeConsumerOwnership*;
+ android::ASurfaceTexture_releaseConsumerOwnership*;
+ android::ASurfaceTexture_dequeueBuffer*;
+ android::SurfaceTexture*;
};
+ ASurfaceTexture_acquireANativeWindow;
+ ASurfaceTexture_attachToGLContext;
+ ASurfaceTexture_detachFromGLContext;
+ ASurfaceTexture_getTimestamp;
+ ASurfaceTexture_getTransformMatrix;
+ ASurfaceTexture_updateTexImage;
} LIBNATIVEDISPLAY;
diff --git a/libs/gui/surfacetexture/EGLConsumer.cpp b/libs/nativedisplay/surfacetexture/EGLConsumer.cpp
similarity index 99%
rename from libs/gui/surfacetexture/EGLConsumer.cpp
rename to libs/nativedisplay/surfacetexture/EGLConsumer.cpp
index 1f0f52c..2f31888 100644
--- a/libs/gui/surfacetexture/EGLConsumer.cpp
+++ b/libs/nativedisplay/surfacetexture/EGLConsumer.cpp
@@ -24,8 +24,8 @@
#include <cutils/compiler.h>
#include <gui/BufferItem.h>
#include <gui/BufferQueue.h>
-#include <gui/surfacetexture/EGLConsumer.h>
-#include <gui/surfacetexture/SurfaceTexture.h>
+#include <surfacetexture/EGLConsumer.h>
+#include <surfacetexture/SurfaceTexture.h>
#include <inttypes.h>
#include <private/gui/SyncFeatures.h>
#include <utils/Log.h>
diff --git a/libs/gui/surfacetexture/ImageConsumer.cpp b/libs/nativedisplay/surfacetexture/ImageConsumer.cpp
similarity index 97%
rename from libs/gui/surfacetexture/ImageConsumer.cpp
rename to libs/nativedisplay/surfacetexture/ImageConsumer.cpp
index 4bc4a7b..16afc68 100644
--- a/libs/gui/surfacetexture/ImageConsumer.cpp
+++ b/libs/nativedisplay/surfacetexture/ImageConsumer.cpp
@@ -15,8 +15,8 @@
*/
#include <gui/BufferQueue.h>
-#include <gui/surfacetexture/ImageConsumer.h>
-#include <gui/surfacetexture/SurfaceTexture.h>
+#include <surfacetexture/ImageConsumer.h>
+#include <surfacetexture/SurfaceTexture.h>
// Macro for including the SurfaceTexture name in log messages
#define IMG_LOGE(x, ...) ALOGE("[%s] " x, st.mName.string(), ##__VA_ARGS__)
diff --git a/libs/gui/surfacetexture/SurfaceTexture.cpp b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp
similarity index 90%
rename from libs/gui/surfacetexture/SurfaceTexture.cpp
rename to libs/nativedisplay/surfacetexture/SurfaceTexture.cpp
index 25e5618..62db6d0 100644
--- a/libs/gui/surfacetexture/SurfaceTexture.cpp
+++ b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp
@@ -16,9 +16,9 @@
#include <cutils/compiler.h>
#include <gui/BufferQueue.h>
-#include <gui/surfacetexture/ImageConsumer.h>
-#include <gui/surfacetexture/SurfaceTexture.h>
-#include <gui/surfacetexture/surface_texture_platform.h>
+#include <surfacetexture/ImageConsumer.h>
+#include <surfacetexture/SurfaceTexture.h>
+#include <surfacetexture/surface_texture_platform.h>
#include <math/mat4.h>
#include <system/window.h>
#include <utils/Trace.h>
@@ -487,42 +487,4 @@
return buffer;
}
-unsigned int ASurfaceTexture_getCurrentTextureTarget(ASurfaceTexture* st) {
- return st->consumer->getCurrentTextureTarget();
-}
-
-void ASurfaceTexture_takeConsumerOwnership(ASurfaceTexture* texture) {
- texture->consumer->takeConsumerOwnership();
-}
-
-void ASurfaceTexture_releaseConsumerOwnership(ASurfaceTexture* texture) {
- texture->consumer->releaseConsumerOwnership();
-}
-
-AHardwareBuffer* ASurfaceTexture_dequeueBuffer(ASurfaceTexture* st, int* outSlotid,
- android_dataspace* outDataspace,
- float* outTransformMatrix, bool* outNewContent,
- ASurfaceTexture_createReleaseFence createFence,
- ASurfaceTexture_fenceWait fenceWait, void* handle) {
- sp<GraphicBuffer> buffer;
- *outNewContent = false;
- bool queueEmpty;
- do {
- buffer = st->consumer->dequeueBuffer(outSlotid, outDataspace, outTransformMatrix,
- &queueEmpty, createFence, fenceWait, handle);
- if (!queueEmpty) {
- *outNewContent = true;
- }
- } while (buffer.get() && (!queueEmpty));
- return reinterpret_cast<AHardwareBuffer*>(buffer.get());
-}
-
-ASurfaceTexture* ASurfaceTexture_create(sp<SurfaceTexture> consumer,
- sp<IGraphicBufferProducer> producer) {
- ASurfaceTexture* ast = new ASurfaceTexture;
- ast->consumer = consumer;
- ast->producer = producer;
- return ast;
-}
-
} // namespace android
diff --git a/libs/nativedisplay/surfacetexture/surface_texture.cpp b/libs/nativedisplay/surfacetexture/surface_texture.cpp
new file mode 100644
index 0000000..1670fbb
--- /dev/null
+++ b/libs/nativedisplay/surfacetexture/surface_texture.cpp
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2018 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 <android/surface_texture.h>
+#include <android/surface_texture_jni.h>
+
+#define LOG_TAG "ASurfaceTexture"
+
+#include <utils/Log.h>
+
+#include <gui/Surface.h>
+
+#include <surfacetexture/surface_texture_platform.h>
+#include <surfacetexture/SurfaceTexture.h>
+
+#include <mutex>
+
+#include <jni.h>
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedLocalRef.h>
+
+struct ASurfaceTexture {
+ android::sp<android::SurfaceTexture> consumer;
+ android::sp<android::IGraphicBufferProducer> producer;
+};
+
+using namespace android;
+
+const char* const kSurfaceTextureClassPathName = "android/graphics/SurfaceTexture";
+
+struct fields_t {
+ jfieldID surfaceTexture;
+ jfieldID producer;
+};
+static fields_t fields;
+static std::once_flag sInitFieldsOnce;
+
+#define ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID "mSurfaceTexture"
+#define ANDROID_GRAPHICS_PRODUCER_JNI_ID "mProducer"
+
+static void SurfaceTexture_classInit(JNIEnv* env, jclass clazz)
+{
+ fields.surfaceTexture = env->GetFieldID(clazz,
+ ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID, "J");
+ if (fields.surfaceTexture == NULL) {
+ ALOGE("can't find android/graphics/SurfaceTexture.%s",
+ ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID);
+ }
+ fields.producer = env->GetFieldID(clazz,
+ ANDROID_GRAPHICS_PRODUCER_JNI_ID, "J");
+ if (fields.producer == NULL) {
+ ALOGE("can't find android/graphics/SurfaceTexture.%s",
+ ANDROID_GRAPHICS_PRODUCER_JNI_ID);
+ }
+}
+
+static inline jclass FindClassOrDie(JNIEnv* env, const char* class_name) {
+ jclass clazz = env->FindClass(class_name);
+ LOG_ALWAYS_FATAL_IF(clazz == NULL, "Unable to find class %s", class_name);
+ return clazz;
+}
+
+static void register_android_graphics_SurfaceTexture(JNIEnv* env)
+{
+ // Cache some fields.
+ ScopedLocalRef<jclass> klass(env, FindClassOrDie(env, kSurfaceTextureClassPathName));
+ SurfaceTexture_classInit(env, klass.get());
+}
+
+static bool android_SurfaceTexture_isInstanceOf(JNIEnv* env, jobject thiz) {
+ std::call_once(sInitFieldsOnce, [=]() {
+ register_android_graphics_SurfaceTexture(env);
+ });
+
+ jclass surfaceTextureClass = env->FindClass(kSurfaceTextureClassPathName);
+ return env->IsInstanceOf(thiz, surfaceTextureClass);
+}
+
+static sp<SurfaceTexture> SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz) {
+ std::call_once(sInitFieldsOnce, [=]() {
+ register_android_graphics_SurfaceTexture(env);
+ });
+
+ return (SurfaceTexture*)env->GetLongField(thiz, fields.surfaceTexture);
+}
+
+static sp<IGraphicBufferProducer> SurfaceTexture_getProducer(JNIEnv* env, jobject thiz) {
+ std::call_once(sInitFieldsOnce, [=]() {
+ register_android_graphics_SurfaceTexture(env);
+ });
+
+ return (IGraphicBufferProducer*)env->GetLongField(thiz, fields.producer);
+}
+
+// The following functions implement NDK API.
+ASurfaceTexture* ASurfaceTexture_fromSurfaceTexture(JNIEnv* env, jobject surfacetexture) {
+ if (!surfacetexture || !android_SurfaceTexture_isInstanceOf(env, surfacetexture)) {
+ return nullptr;
+ }
+ ASurfaceTexture* ast = new ASurfaceTexture;
+ ast->consumer = SurfaceTexture_getSurfaceTexture(env, surfacetexture);
+ ast->producer = SurfaceTexture_getProducer(env, surfacetexture);
+ return ast;
+}
+
+ANativeWindow* ASurfaceTexture_acquireANativeWindow(ASurfaceTexture* st) {
+ sp<Surface> surface = new Surface(st->producer);
+ ANativeWindow* win(surface.get());
+ ANativeWindow_acquire(win);
+ return win;
+}
+
+void ASurfaceTexture_release(ASurfaceTexture* st) {
+ delete st;
+}
+
+int ASurfaceTexture_attachToGLContext(ASurfaceTexture* st, uint32_t tex) {
+ return st->consumer->attachToContext(tex);
+}
+
+int ASurfaceTexture_detachFromGLContext(ASurfaceTexture* st) {
+ return st->consumer->detachFromContext();
+}
+
+int ASurfaceTexture_updateTexImage(ASurfaceTexture* st) {
+ return st->consumer->updateTexImage();
+}
+
+void ASurfaceTexture_getTransformMatrix(ASurfaceTexture* st, float mtx[16]) {
+ st->consumer->getTransformMatrix(mtx);
+}
+
+int64_t ASurfaceTexture_getTimestamp(ASurfaceTexture* st) {
+ return st->consumer->getTimestamp();
+}
+
+// The following functions are private/unstable API.
+namespace android {
+
+unsigned int ASurfaceTexture_getCurrentTextureTarget(ASurfaceTexture* st) {
+ return st->consumer->getCurrentTextureTarget();
+}
+
+void ASurfaceTexture_takeConsumerOwnership(ASurfaceTexture* texture) {
+ texture->consumer->takeConsumerOwnership();
+}
+
+void ASurfaceTexture_releaseConsumerOwnership(ASurfaceTexture* texture) {
+ texture->consumer->releaseConsumerOwnership();
+}
+
+AHardwareBuffer* ASurfaceTexture_dequeueBuffer(ASurfaceTexture* st, int* outSlotid,
+ android_dataspace* outDataspace,
+ float* outTransformMatrix, bool* outNewContent,
+ ASurfaceTexture_createReleaseFence createFence,
+ ASurfaceTexture_fenceWait fenceWait, void* handle) {
+ sp<GraphicBuffer> buffer;
+ *outNewContent = false;
+ bool queueEmpty;
+ do {
+ buffer = st->consumer->dequeueBuffer(outSlotid, outDataspace, outTransformMatrix,
+ &queueEmpty, createFence, fenceWait, handle);
+ if (!queueEmpty) {
+ *outNewContent = true;
+ }
+ } while (buffer.get() && (!queueEmpty));
+ return reinterpret_cast<AHardwareBuffer*>(buffer.get());
+}
+
+} // namespace android
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index 842af18..a60bc4d 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -158,6 +158,13 @@
return query(window, NATIVE_WINDOW_DATASPACE);
}
+int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate) {
+ if (!window || !query(window, NATIVE_WINDOW_IS_VALID) || frameRate < 0) {
+ return -EINVAL;
+ }
+ return native_window_set_frame_rate(window, frameRate);
+}
+
/**************************************************************************************************
* vndk-stable
**************************************************************************************************/
diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h
index 3e436e3..262aee3 100644
--- a/libs/nativewindow/include/android/native_window.h
+++ b/libs/nativewindow/include/android/native_window.h
@@ -230,6 +230,39 @@
#endif // __ANDROID_API__ >= 28
+#if __ANDROID_API__ >= 30
+
+/**
+ * Sets the intended frame rate for this window.
+ *
+ * On devices that are capable of running the display at different refresh
+ * rates, the system may choose a display refresh rate to better match this
+ * window's frame rate. Usage of this API won't introduce frame rate throttling,
+ * or affect other aspects of the application's frame production
+ * pipeline. However, because the system may change the display refresh rate,
+ * calls to this function may result in changes to Choreographer callback
+ * timings, and changes to the time interval at which the system releases
+ * buffers back to the application.
+ *
+ * Note that this only has an effect for windows presented on the display. If
+ * this ANativeWindow is consumed by something other than the system compositor,
+ * e.g. a media codec, this call has no effect.
+ *
+ * Available since API level 30.
+ *
+ * \param frameRate The intended frame rate of this window, in frames per
+ * second. 0 is a special value that indicates the app will accept the system's
+ * choice for the display frame rate, which is the default behavior if this
+ * function isn't called. The frameRate param does *not* need to be a valid
+ * refresh rate for this device's display - e.g., it's fine to pass 30fps to a
+ * device that can only run the display at 60fps.
+ *
+ * \return 0 for success, -EINVAL if the window or frame rate are invalid.
+ */
+int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate) __INTRODUCED_IN(30);
+
+#endif // __ANDROID_API__ >= 30
+
#ifdef __cplusplus
};
#endif
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 1814ab5..14f7214 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -34,12 +34,12 @@
#include <cutils/native_handle.h>
#include <errno.h>
#include <limits.h>
+#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <sys/cdefs.h>
#include <system/graphics.h>
#include <unistd.h>
-#include <stdbool.h>
// system/window.h is a superset of the vndk and apex apis
#include <apex/window.h>
@@ -247,6 +247,7 @@
NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT = 37, /* private */
NATIVE_WINDOW_GET_LAST_DEQUEUE_DURATION = 38, /* private */
NATIVE_WINDOW_GET_LAST_QUEUE_DURATION = 39, /* private */
+ NATIVE_WINDOW_SET_FRAME_RATE = 40,
// clang-format on
};
@@ -1008,4 +1009,8 @@
return window->perform(window, NATIVE_WINDOW_SET_AUTO_PREROTATION, autoPrerotation);
}
+static inline int native_window_set_frame_rate(struct ANativeWindow* window, float frameRate) {
+ return window->perform(window, NATIVE_WINDOW_SET_FRAME_RATE, (double)frameRate);
+}
+
__END_DECLS
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index f59e8f0..3002da2 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -43,6 +43,7 @@
ANativeWindow_setDequeueTimeout; # apex # introduced=30
ANativeWindow_setSharedBufferMode; # llndk
ANativeWindow_setSwapInterval; # llndk
+ ANativeWindow_setFrameRate; # introduced=30
ANativeWindow_setUsage; # llndk
ANativeWindow_unlockAndPost;
local:
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index 348377e..2e3ab4c 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -57,6 +57,10 @@
"gl/ImageManager.cpp",
"gl/Program.cpp",
"gl/ProgramCache.cpp",
+ "gl/filters/BlurFilter.cpp",
+ "gl/filters/LensBlurFilter.cpp",
+ "gl/filters/GaussianBlurFilter.cpp",
+ "gl/filters/GenericProgram.cpp",
],
}
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 0748dfb..e257704 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -49,6 +49,9 @@
#include "GLShadowVertexGenerator.h"
#include "Program.h"
#include "ProgramCache.h"
+#include "filters/BlurFilter.h"
+#include "filters/GaussianBlurFilter.h"
+#include "filters/LensBlurFilter.h"
extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
@@ -422,6 +425,18 @@
mTraceGpuCompletion = true;
mFlushTracer = std::make_unique<FlushTracer>(this);
}
+
+ if (args.supportsBackgroundBlur) {
+ char isGaussian[PROPERTY_VALUE_MAX];
+ property_get("debug.sf.gaussianBlur", isGaussian, "1");
+ if (atoi(isGaussian)) {
+ mBlurFilter = new GaussianBlurFilter(*this);
+ } else {
+ mBlurFilter = new LensBlurFilter(*this);
+ }
+ checkErrors("BlurFilter creation");
+ }
+
mImageManager = std::make_unique<ImageManager>(this);
mDrawingBuffer = createFramebuffer();
}
@@ -871,11 +886,19 @@
}
void GLESRenderEngine::checkErrors() const {
+ checkErrors(nullptr);
+}
+
+void GLESRenderEngine::checkErrors(const char* tag) const {
do {
// there could be more than one error flag
GLenum error = glGetError();
if (error == GL_NO_ERROR) break;
- ALOGE("GL error 0x%04x", int(error));
+ if (tag == nullptr) {
+ ALOGE("GL error 0x%04x", int(error));
+ } else {
+ ALOGE("GL error: %s -> 0x%04x", tag, int(error));
+ }
} while (true);
}
@@ -937,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) {
@@ -957,13 +980,36 @@
return BAD_VALUE;
}
- BindNativeBufferAsFramebuffer fbo(*this, buffer, useFramebufferCache);
+ std::unique_ptr<BindNativeBufferAsFramebuffer> fbo;
+ // Let's find the topmost layer requesting background blur (if any.)
+ // 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;
+ }
+ }
+ }
- if (fbo.getStatus() != NO_ERROR) {
- ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).",
- buffer->handle);
- checkErrors();
- return fbo.getStatus();
+ if (blurLayer == nullptr) {
+ fbo = std::make_unique<BindNativeBufferAsFramebuffer>(*this, buffer, useFramebufferCache);
+ if (fbo->getStatus() != NO_ERROR) {
+ ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).",
+ buffer->handle);
+ checkErrors();
+ return fbo->getStatus();
+ }
+ setViewportAndProjection(display.physicalDisplay, display.clip);
+ } else {
+ setViewportAndProjection(display.physicalDisplay, display.clip);
+ auto status = mBlurFilter->setAsDrawTarget(display);
+ if (status != NO_ERROR) {
+ ALOGE("Failed to prepare blur filter! Aborting GPU composition for buffer (%p).",
+ buffer->handle);
+ checkErrors();
+ return status;
+ }
}
// clear the entire buffer, sometimes when we reuse buffers we'd persist
@@ -973,8 +1019,6 @@
// opaque layers.
clearWithColor(0.0, 0.0, 0.0, 0.0);
- setViewportAndProjection(display.physicalDisplay, display.clip);
-
setOutputDataSpace(display.outputDataspace);
setDisplayMaxLuminance(display.maxLuminance);
@@ -991,41 +1035,70 @@
.setTexCoords(2 /* size */)
.setCropCoords(2 /* size */)
.build();
- for (auto layer : layers) {
- mState.maxMasteringLuminance = layer.source.buffer.maxMasteringLuminance;
- mState.maxContentLuminance = layer.source.buffer.maxContentLuminance;
- mState.projectionMatrix = projectionMatrix * layer.geometry.positionTransform;
+ 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);
+ checkErrors("Can't render first blur pass");
+ return status;
+ }
- const FloatRect bounds = layer.geometry.boundaries;
+ fbo = std::make_unique<BindNativeBufferAsFramebuffer>(*this, buffer,
+ useFramebufferCache);
+ status = fbo->getStatus();
+ if (status != NO_ERROR) {
+ ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).",
+ buffer->handle);
+ checkErrors("Can't bind native framebuffer");
+ return status;
+ }
+ setViewportAndProjection(display.physicalDisplay, display.clip);
+
+ status = mBlurFilter->render();
+ if (status != NO_ERROR) {
+ ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).",
+ buffer->handle);
+ checkErrors("Can't render blur filter");
+ return status;
+ }
+ }
+
+ mState.maxMasteringLuminance = layer->source.buffer.maxMasteringLuminance;
+ mState.maxContentLuminance = layer->source.buffer.maxContentLuminance;
+ mState.projectionMatrix = projectionMatrix * layer->geometry.positionTransform;
+
+ 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);
@@ -1035,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 f41eda2..45c85de 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -46,6 +46,7 @@
namespace gl {
class GLImage;
+class BlurFilter;
class GLESRenderEngine : public impl::RenderEngine {
public:
@@ -70,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;
@@ -117,6 +119,7 @@
std::unique_ptr<Framebuffer> createFramebuffer();
std::unique_ptr<Image> createImage();
void checkErrors() const;
+ void checkErrors(const char* tag) const;
void setScissor(const Rect& region);
void disableScissor();
bool waitSync(EGLSyncKHR sync, EGLint flags);
@@ -228,6 +231,9 @@
std::unique_ptr<Framebuffer> mDrawingBuffer;
+ // Blur effect processor, only instantiated when a layer requests it.
+ BlurFilter* mBlurFilter = nullptr;
+
class FlushTracer {
public:
FlushTracer(GLESRenderEngine* engine);
@@ -251,6 +257,11 @@
};
friend class FlushTracer;
friend class ImageManager;
+ friend class GLFramebuffer;
+ friend class BlurFilter;
+ friend class GaussianBlurFilter;
+ friend class LensBlurFilter;
+ friend class GenericProgram;
std::unique_ptr<FlushTracer> mFlushTracer;
std::unique_ptr<ImageManager> mImageManager = std::make_unique<ImageManager>(this);
};
diff --git a/libs/renderengine/gl/GLFramebuffer.cpp b/libs/renderengine/gl/GLFramebuffer.cpp
index 5fbb5ba..091eac9 100644
--- a/libs/renderengine/gl/GLFramebuffer.cpp
+++ b/libs/renderengine/gl/GLFramebuffer.cpp
@@ -20,8 +20,8 @@
#include <GLES/gl.h>
#include <GLES/glext.h>
-#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
+#include <GLES3/gl3.h>
#include <gui/DebugEGLImageTracker.h>
#include <nativebase/nativebase.h>
#include <utils/Trace.h>
@@ -32,14 +32,23 @@
namespace gl {
GLFramebuffer::GLFramebuffer(GLESRenderEngine& engine)
+ : GLFramebuffer(engine, false /* multiTarget */) {}
+
+GLFramebuffer::GLFramebuffer(GLESRenderEngine& engine, bool multiTarget)
: mEngine(engine), mEGLDisplay(engine.getEGLDisplay()), mEGLImage(EGL_NO_IMAGE_KHR) {
glGenTextures(1, &mTextureName);
+ if (multiTarget) {
+ glGenTextures(1, &mSecondaryTextureName);
+ }
glGenFramebuffers(1, &mFramebufferName);
}
GLFramebuffer::~GLFramebuffer() {
glDeleteFramebuffers(1, &mFramebufferName);
glDeleteTextures(1, &mTextureName);
+ if (mSecondaryTextureName != -1) {
+ glDeleteTextures(1, &mSecondaryTextureName);
+ }
}
bool GLFramebuffer::setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected,
@@ -68,6 +77,55 @@
return true;
}
+void GLFramebuffer::allocateBuffers(uint32_t width, uint32_t height) {
+ ATRACE_CALL();
+
+ glBindTexture(GL_TEXTURE_2D, mTextureName);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
+
+ const bool multiTarget = mSecondaryTextureName != -1;
+ if (multiTarget) {
+ glBindTexture(GL_TEXTURE_2D, mSecondaryTextureName);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
+ }
+
+ mBufferHeight = height;
+ mBufferWidth = width;
+ mEngine.checkErrors("Allocating Fbo texture");
+
+ bind();
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextureName, 0);
+ if (multiTarget) {
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D,
+ mSecondaryTextureName, 0);
+ GLenum buffers[] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};
+ glDrawBuffers(2, buffers);
+ }
+ mStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ unbind();
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ if (mStatus != GL_FRAMEBUFFER_COMPLETE) {
+ ALOGE("Frame buffer is not complete. Error %d", mStatus);
+ }
+}
+
+void GLFramebuffer::bind() const {
+ glBindFramebuffer(GL_FRAMEBUFFER, mFramebufferName);
+}
+
+void GLFramebuffer::unbind() const {
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
} // namespace gl
} // namespace renderengine
} // namespace android
diff --git a/libs/renderengine/gl/GLFramebuffer.h b/libs/renderengine/gl/GLFramebuffer.h
index b7650bb..668685a 100644
--- a/libs/renderengine/gl/GLFramebuffer.h
+++ b/libs/renderengine/gl/GLFramebuffer.h
@@ -20,6 +20,7 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
#include <renderengine/Framebuffer.h>
struct ANativeWindowBuffer;
@@ -33,22 +34,30 @@
class GLFramebuffer : public renderengine::Framebuffer {
public:
explicit GLFramebuffer(GLESRenderEngine& engine);
+ explicit GLFramebuffer(GLESRenderEngine& engine, bool multiTarget);
~GLFramebuffer() override;
bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected,
const bool useFramebufferCache) override;
+ void allocateBuffers(uint32_t width, uint32_t height);
EGLImageKHR getEGLImage() const { return mEGLImage; }
uint32_t getTextureName() const { return mTextureName; }
+ uint32_t getSecondaryTextureName() const { return mSecondaryTextureName; }
uint32_t getFramebufferName() const { return mFramebufferName; }
int32_t getBufferHeight() const { return mBufferHeight; }
int32_t getBufferWidth() const { return mBufferWidth; }
+ GLenum getStatus() const { return mStatus; }
+ void bind() const;
+ void unbind() const;
private:
GLESRenderEngine& mEngine;
EGLDisplay mEGLDisplay;
EGLImageKHR mEGLImage;
bool usingFramebufferCache = false;
+ GLenum mStatus = GL_FRAMEBUFFER_UNSUPPORTED;
uint32_t mTextureName, mFramebufferName;
+ uint32_t mSecondaryTextureName = -1;
int32_t mBufferHeight = 0;
int32_t mBufferWidth = 0;
diff --git a/libs/renderengine/gl/filters/BlurFilter.cpp b/libs/renderengine/gl/filters/BlurFilter.cpp
new file mode 100644
index 0000000..a18a999
--- /dev/null
+++ b/libs/renderengine/gl/filters/BlurFilter.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "BlurFilter.h"
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES3/gl3.h>
+#include <GLES3/gl3ext.h>
+#include <ui/GraphicTypes.h>
+#include <cstdint>
+
+#include <utils/Trace.h>
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+BlurFilter::BlurFilter(GLESRenderEngine& engine)
+ : mEngine(engine), mCompositionFbo(engine), mBlurredFbo(engine), mSimpleProgram(engine) {
+ mSimpleProgram.compile(getVertexShader(), getSimpleFragShader());
+ mSPosLoc = mSimpleProgram.getAttributeLocation("aPosition");
+ mSUvLoc = mSimpleProgram.getAttributeLocation("aUV");
+ mSTextureLoc = mSimpleProgram.getUniformLocation("uTexture");
+}
+
+status_t BlurFilter::setAsDrawTarget(const DisplaySettings& display) {
+ ATRACE_NAME("BlurFilter::setAsDrawTarget");
+
+ if (!mTexturesAllocated) {
+ mDisplayWidth = display.physicalDisplay.width();
+ mDisplayHeight = display.physicalDisplay.height();
+ mCompositionFbo.allocateBuffers(mDisplayWidth, mDisplayHeight);
+
+ // Let's use mimap filtering on the offscreen composition texture,
+ // this will drastically improve overall shader quality.
+ glBindTexture(GL_TEXTURE_2D, mCompositionFbo.getTextureName());
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 3);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ const uint32_t fboWidth = floorf(mDisplayWidth * kFboScale);
+ const uint32_t fboHeight = floorf(mDisplayHeight * kFboScale);
+ mBlurredFbo.allocateBuffers(fboWidth, fboHeight);
+ allocateTextures();
+ mTexturesAllocated = true;
+ }
+
+ if (mBlurredFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) {
+ ALOGE("Invalid blur buffer");
+ return mBlurredFbo.getStatus();
+ }
+ if (mCompositionFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) {
+ ALOGE("Invalid composition buffer");
+ return mCompositionFbo.getStatus();
+ }
+
+ mCompositionFbo.bind();
+ glViewport(0, 0, mCompositionFbo.getBufferWidth(), mCompositionFbo.getBufferHeight());
+ return NO_ERROR;
+}
+
+void BlurFilter::drawMesh(GLuint uv, GLuint position) {
+ GLfloat positions[] = {-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f};
+ GLfloat texCoords[] = {0.0, 0.0, 0.0, 1.0f, 1.0f, 1.0f, 1.0f, 0};
+
+ // set attributes
+ glEnableVertexAttribArray(uv);
+ glVertexAttribPointer(uv, 2 /* size */, GL_FLOAT, GL_FALSE, 0, texCoords);
+ glEnableVertexAttribArray(position);
+ glVertexAttribPointer(position, 2 /* size */, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat),
+ positions);
+
+ // draw mesh
+ glDrawArrays(GL_TRIANGLE_FAN, 0 /* first */, 4 /* count */);
+ mEngine.checkErrors("Drawing blur mesh");
+}
+
+status_t BlurFilter::render() {
+ ATRACE_NAME("BlurFilter::render");
+
+ // Now let's scale our blur up
+ mSimpleProgram.useProgram();
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, mBlurredFbo.getTextureName());
+ glUniform1i(mSTextureLoc, 0);
+ mEngine.checkErrors("Setting final pass uniforms");
+
+ drawMesh(mSUvLoc, mSPosLoc);
+
+ glUseProgram(0);
+ return NO_ERROR;
+}
+
+string BlurFilter::getVertexShader() const {
+ return R"SHADER(
+ #version 310 es
+ precision lowp float;
+
+ in vec2 aPosition;
+ in mediump vec2 aUV;
+ out mediump vec2 vUV;
+
+ void main() {
+ vUV = aUV;
+ gl_Position = vec4(aPosition, 0.0, 1.0);
+ }
+ )SHADER";
+}
+
+string BlurFilter::getSimpleFragShader() const {
+ string shader = R"SHADER(
+ #version 310 es
+ precision lowp float;
+
+ in mediump vec2 vUV;
+ out vec4 fragColor;
+
+ uniform sampler2D uTexture;
+
+ void main() {
+ fragColor = texture(uTexture, vUV);
+ }
+ )SHADER";
+ return shader;
+}
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/gl/filters/BlurFilter.h b/libs/renderengine/gl/filters/BlurFilter.h
new file mode 100644
index 0000000..e265b51
--- /dev/null
+++ b/libs/renderengine/gl/filters/BlurFilter.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <ui/GraphicTypes.h>
+#include "../GLESRenderEngine.h"
+#include "../GLFramebuffer.h"
+#include "GenericProgram.h"
+
+using namespace std;
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+class BlurFilter {
+public:
+ // Downsample FBO to improve performance
+ static constexpr float kFboScale = 0.25f;
+
+ explicit BlurFilter(GLESRenderEngine& engine);
+ virtual ~BlurFilter(){};
+
+ // Set up render targets, redirecting output to offscreen texture.
+ status_t setAsDrawTarget(const DisplaySettings&);
+ // Allocate any textures needed for the filter.
+ virtual void allocateTextures() = 0;
+ // Execute blur passes, rendering to offscreen texture.
+ virtual status_t prepare(uint32_t radius) = 0;
+ // Render blur to the bound framebuffer (screen).
+ status_t render();
+
+protected:
+ void drawMesh(GLuint uv, GLuint position);
+ string getSimpleFragShader() const;
+ string getVertexShader() const;
+
+ GLESRenderEngine& mEngine;
+ // Frame buffer holding the composited background.
+ GLFramebuffer mCompositionFbo;
+ // Frame buffer holding the blur result.
+ GLFramebuffer mBlurredFbo;
+ uint32_t mDisplayWidth;
+ uint32_t mDisplayHeight;
+
+private:
+ bool mTexturesAllocated = false;
+
+ GenericProgram mSimpleProgram;
+ GLuint mSPosLoc;
+ GLuint mSUvLoc;
+ GLuint mSTextureLoc;
+};
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/gl/filters/GaussianBlurFilter.cpp b/libs/renderengine/gl/filters/GaussianBlurFilter.cpp
new file mode 100644
index 0000000..f5ba02a
--- /dev/null
+++ b/libs/renderengine/gl/filters/GaussianBlurFilter.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "GaussianBlurFilter.h"
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES3/gl3.h>
+#include <GLES3/gl3ext.h>
+#include <ui/GraphicTypes.h>
+#include <cstdint>
+
+#include <utils/Trace.h>
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+GaussianBlurFilter::GaussianBlurFilter(GLESRenderEngine& engine)
+ : BlurFilter(engine),
+ mVerticalPassFbo(engine),
+ mVerticalProgram(engine),
+ mHorizontalProgram(engine) {
+ mVerticalProgram.compile(getVertexShader(), getFragmentShader(false));
+ mVPosLoc = mVerticalProgram.getAttributeLocation("aPosition");
+ mVUvLoc = mVerticalProgram.getAttributeLocation("aUV");
+ mVTextureLoc = mVerticalProgram.getUniformLocation("uTexture");
+ mVSizeLoc = mVerticalProgram.getUniformLocation("uSize");
+ mVRadiusLoc = mVerticalProgram.getUniformLocation("uRadius");
+
+ mHorizontalProgram.compile(getVertexShader(), getFragmentShader(true));
+ mHPosLoc = mHorizontalProgram.getAttributeLocation("aPosition");
+ mHUvLoc = mHorizontalProgram.getAttributeLocation("aUV");
+ mHTextureLoc = mHorizontalProgram.getUniformLocation("uTexture");
+ mHSizeLoc = mHorizontalProgram.getUniformLocation("uSize");
+ mHRadiusLoc = mHorizontalProgram.getUniformLocation("uRadius");
+}
+
+void GaussianBlurFilter::allocateTextures() {
+ mVerticalPassFbo.allocateBuffers(mBlurredFbo.getBufferWidth(), mBlurredFbo.getBufferHeight());
+}
+
+status_t GaussianBlurFilter::prepare(uint32_t radius) {
+ ATRACE_NAME("GaussianBlurFilter::prepare");
+
+ if (mVerticalPassFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) {
+ ALOGE("Invalid vertical FBO");
+ return mVerticalPassFbo.getStatus();
+ }
+ if (!mVerticalProgram.isValid()) {
+ ALOGE("Invalid vertical shader");
+ return GL_INVALID_OPERATION;
+ }
+ if (!mHorizontalProgram.isValid()) {
+ ALOGE("Invalid horizontal shader");
+ return GL_INVALID_OPERATION;
+ }
+
+ // First, we'll apply the vertical pass, that receives the flattened background layers.
+ mVerticalPassFbo.bind();
+ mVerticalProgram.useProgram();
+
+ // set uniforms
+ auto width = mVerticalPassFbo.getBufferWidth();
+ auto height = mVerticalPassFbo.getBufferHeight();
+ auto radiusF = fmax(1.0f, radius * kFboScale);
+ glViewport(0, 0, width, height);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, mCompositionFbo.getTextureName());
+ glGenerateMipmap(GL_TEXTURE_2D);
+ glUniform1i(mVTextureLoc, 0);
+ glUniform2f(mVSizeLoc, width, height);
+ glUniform1f(mVRadiusLoc, radiusF);
+ mEngine.checkErrors("Setting vertical-diagonal pass uniforms");
+
+ drawMesh(mVUvLoc, mVPosLoc);
+
+ // Blur vertically on a secondary pass
+ mBlurredFbo.bind();
+ mHorizontalProgram.useProgram();
+
+ // set uniforms
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, mVerticalPassFbo.getTextureName());
+ glUniform1i(mHTextureLoc, 0);
+ glUniform2f(mHSizeLoc, width, height);
+ glUniform1f(mHRadiusLoc, radiusF);
+ mEngine.checkErrors("Setting vertical pass uniforms");
+
+ drawMesh(mHUvLoc, mHPosLoc);
+
+ // reset active texture
+ mBlurredFbo.unbind();
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ // unbind program
+ glUseProgram(0);
+
+ return NO_ERROR;
+}
+
+string GaussianBlurFilter::getFragmentShader(bool horizontal) const {
+ string shader = "#version 310 es\n#define DIRECTION ";
+ shader += (horizontal ? "1" : "0");
+ shader += R"SHADER(
+ precision lowp float;
+
+ uniform sampler2D uTexture;
+ uniform vec2 uSize;
+ uniform float uRadius;
+
+ mediump in vec2 vUV;
+ out vec4 fragColor;
+
+ #define PI 3.14159265359
+ #define THETA 0.352
+ #define MU 0.0
+ #define A 1.0 / (THETA * sqrt(2.0 * PI))
+ #define K 1.0 / (2.0 * THETA * THETA)
+ #define MAX_SAMPLES 10
+
+ float gaussianBellCurve(float x) {
+ float tmp = (x - MU);
+ return exp(-K * tmp * tmp);
+ }
+
+ vec3 gaussianBlur(sampler2D texture, mediump vec2 uv, float size,
+ mediump vec2 direction, float radius) {
+ float totalWeight = 0.0;
+ vec3 blurred = vec3(0.);
+ int samples = min(int(ceil(radius / 2.0)), MAX_SAMPLES);
+ float inc = radius / (size * 2.0);
+
+ for (int i = -samples; i <= samples; i++) {
+ float normalized = float(i) / float(samples);
+ float weight = gaussianBellCurve(normalized);
+ float radInc = inc * normalized;
+ blurred += weight * (texture(texture, uv + radInc * direction)).rgb;;
+ totalWeight += weight;
+ }
+
+ return blurred / totalWeight;
+ }
+
+ void main() {
+ #if DIRECTION == 1
+ vec3 color = gaussianBlur(uTexture, vUV, uSize.x, vec2(1.0, 0.0), uRadius);
+ #else
+ vec3 color = gaussianBlur(uTexture, vUV, uSize.y, vec2(0.0, 1.0), uRadius);
+ #endif
+ fragColor = vec4(color, 1.0);
+ }
+
+ )SHADER";
+ return shader;
+}
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/gl/filters/GaussianBlurFilter.h b/libs/renderengine/gl/filters/GaussianBlurFilter.h
new file mode 100644
index 0000000..acf0f07
--- /dev/null
+++ b/libs/renderengine/gl/filters/GaussianBlurFilter.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <ui/GraphicTypes.h>
+#include "../GLESRenderEngine.h"
+#include "../GLFramebuffer.h"
+#include "BlurFilter.h"
+#include "GenericProgram.h"
+
+using namespace std;
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+class GaussianBlurFilter : public BlurFilter {
+public:
+ explicit GaussianBlurFilter(GLESRenderEngine& engine);
+ status_t prepare(uint32_t radius) override;
+ void allocateTextures() override;
+
+private:
+ string getFragmentShader(bool horizontal) const;
+
+ // Initial, vertical render pass
+ GLFramebuffer mVerticalPassFbo;
+
+ // Vertical pass and its uniforms
+ GenericProgram mVerticalProgram;
+ GLuint mVPosLoc;
+ GLuint mVUvLoc;
+ GLuint mVTextureLoc;
+ GLuint mVSizeLoc;
+ GLuint mVRadiusLoc;
+
+ // Horizontal pass and its uniforms
+ GenericProgram mHorizontalProgram;
+ GLuint mHPosLoc;
+ GLuint mHUvLoc;
+ GLuint mHTextureLoc;
+ GLuint mHSizeLoc;
+ GLuint mHRadiusLoc;
+};
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
\ No newline at end of file
diff --git a/libs/renderengine/gl/filters/GenericProgram.cpp b/libs/renderengine/gl/filters/GenericProgram.cpp
new file mode 100644
index 0000000..bb35889
--- /dev/null
+++ b/libs/renderengine/gl/filters/GenericProgram.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "GenericProgram.h"
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+GenericProgram::GenericProgram(GLESRenderEngine& engine) : mEngine(engine) {}
+
+GenericProgram::~GenericProgram() {
+ if (mVertexShaderHandle != 0) {
+ if (mProgramHandle != 0) {
+ glDetachShader(mProgramHandle, mVertexShaderHandle);
+ }
+ glDeleteShader(mVertexShaderHandle);
+ }
+
+ if (mFragmentShaderHandle != 0) {
+ if (mProgramHandle != 0) {
+ glDetachShader(mProgramHandle, mFragmentShaderHandle);
+ }
+ glDeleteShader(mFragmentShaderHandle);
+ }
+
+ if (mProgramHandle != 0) {
+ glDeleteProgram(mProgramHandle);
+ }
+}
+
+void GenericProgram::compile(string vertexShader, string fragmentShader) {
+ mVertexShaderHandle = compileShader(GL_VERTEX_SHADER, vertexShader);
+ mFragmentShaderHandle = compileShader(GL_FRAGMENT_SHADER, fragmentShader);
+ if (mVertexShaderHandle == 0 || mFragmentShaderHandle == 0) {
+ ALOGE("Aborting program creation.");
+ return;
+ }
+ mProgramHandle = createAndLink(mVertexShaderHandle, mFragmentShaderHandle);
+ mEngine.checkErrors("Linking program");
+}
+
+void GenericProgram::useProgram() const {
+ glUseProgram(mProgramHandle);
+}
+
+GLuint GenericProgram::compileShader(GLuint type, string src) const {
+ const GLuint shader = glCreateShader(type);
+ if (shader == 0) {
+ mEngine.checkErrors("Creating shader");
+ return 0;
+ }
+ const GLchar* charSrc = (const GLchar*)src.c_str();
+ glShaderSource(shader, 1, &charSrc, nullptr);
+ glCompileShader(shader);
+
+ GLint isCompiled = 0;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled);
+ if (isCompiled == GL_FALSE) {
+ GLint maxLength = 0;
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
+ string errorLog;
+ errorLog.reserve(maxLength);
+ glGetShaderInfoLog(shader, maxLength, &maxLength, errorLog.data());
+ glDeleteShader(shader);
+ ALOGE("Error compiling shader: %s", errorLog.c_str());
+ return 0;
+ }
+ return shader;
+}
+GLuint GenericProgram::createAndLink(GLuint vertexShader, GLuint fragmentShader) const {
+ const GLuint program = glCreateProgram();
+ mEngine.checkErrors("Creating program");
+
+ glAttachShader(program, vertexShader);
+ glAttachShader(program, fragmentShader);
+ glLinkProgram(program);
+ mEngine.checkErrors("Linking program");
+ return program;
+}
+
+GLuint GenericProgram::getUniformLocation(const string name) const {
+ if (mProgramHandle == 0) {
+ ALOGE("Can't get location of %s on an invalid program.", name.c_str());
+ return -1;
+ }
+ return glGetUniformLocation(mProgramHandle, (const GLchar*)name.c_str());
+}
+
+GLuint GenericProgram::getAttributeLocation(const string name) const {
+ if (mProgramHandle == 0) {
+ ALOGE("Can't get location of %s on an invalid program.", name.c_str());
+ return -1;
+ }
+ return glGetAttribLocation(mProgramHandle, (const GLchar*)name.c_str());
+}
+
+bool GenericProgram::isValid() const {
+ return mProgramHandle != 0;
+}
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/gl/filters/GenericProgram.h b/libs/renderengine/gl/filters/GenericProgram.h
new file mode 100644
index 0000000..6da2a5a
--- /dev/null
+++ b/libs/renderengine/gl/filters/GenericProgram.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <ui/GraphicTypes.h>
+#include "../GLESRenderEngine.h"
+#include "../GLFramebuffer.h"
+
+using namespace std;
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+class GenericProgram {
+public:
+ explicit GenericProgram(GLESRenderEngine& renderEngine);
+ ~GenericProgram();
+ void compile(string vertexShader, string fragmentShader);
+ bool isValid() const;
+ void useProgram() const;
+ GLuint getAttributeLocation(const string name) const;
+ GLuint getUniformLocation(const string name) const;
+
+private:
+ GLuint compileShader(GLuint type, const string src) const;
+ GLuint createAndLink(GLuint vertexShader, GLuint fragmentShader) const;
+
+ GLESRenderEngine& mEngine;
+ GLuint mVertexShaderHandle = 0;
+ GLuint mFragmentShaderHandle = 0;
+ GLuint mProgramHandle = 0;
+};
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/gl/filters/LensBlurFilter.cpp b/libs/renderengine/gl/filters/LensBlurFilter.cpp
new file mode 100644
index 0000000..799deac
--- /dev/null
+++ b/libs/renderengine/gl/filters/LensBlurFilter.cpp
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "LensBlurFilter.h"
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES3/gl3.h>
+#include <GLES3/gl3ext.h>
+#include <ui/GraphicTypes.h>
+#include <cstdint>
+
+#include <utils/Trace.h>
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+// Number of blur samples in shader (for loop)
+static constexpr auto kNumSamples = 12;
+
+LensBlurFilter::LensBlurFilter(GLESRenderEngine& engine)
+ : BlurFilter(engine),
+ mVerticalDiagonalPassFbo(engine, true /* multiTarget */),
+ mVerticalDiagonalProgram(engine),
+ mCombinedProgram(engine) {
+ mVerticalDiagonalProgram.compile(getVertexShader(), getFragmentShader(false));
+ mCombinedProgram.compile(getVertexShader(), getFragmentShader(true));
+
+ mVDPosLoc = mVerticalDiagonalProgram.getAttributeLocation("aPosition");
+ mVDUvLoc = mVerticalDiagonalProgram.getAttributeLocation("aUV");
+ mVDTexture0Loc = mVerticalDiagonalProgram.getUniformLocation("uTexture0");
+ mVDSizeLoc = mVerticalDiagonalProgram.getUniformLocation("uSize");
+ mVDRadiusLoc = mVerticalDiagonalProgram.getUniformLocation("uRadius");
+ mVDNumSamplesLoc = mVerticalDiagonalProgram.getUniformLocation("uNumSamples");
+
+ mCPosLoc = mCombinedProgram.getAttributeLocation("aPosition");
+ mCUvLoc = mCombinedProgram.getAttributeLocation("aUV");
+ mCTexture0Loc = mCombinedProgram.getUniformLocation("uTexture0");
+ mCTexture1Loc = mCombinedProgram.getUniformLocation("uTexture1");
+ mCSizeLoc = mCombinedProgram.getUniformLocation("uSize");
+ mCRadiusLoc = mCombinedProgram.getUniformLocation("uRadius");
+ mCNumSamplesLoc = mCombinedProgram.getUniformLocation("uNumSamples");
+}
+
+void LensBlurFilter::allocateTextures() {
+ mVerticalDiagonalPassFbo.allocateBuffers(mBlurredFbo.getBufferWidth(),
+ mBlurredFbo.getBufferHeight());
+}
+
+status_t LensBlurFilter::prepare(uint32_t radius) {
+ ATRACE_NAME("LensBlurFilter::prepare");
+
+ if (mVerticalDiagonalPassFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) {
+ ALOGE("Invalid vertical-diagonal FBO");
+ return mVerticalDiagonalPassFbo.getStatus();
+ }
+ if (!mVerticalDiagonalProgram.isValid()) {
+ ALOGE("Invalid vertical-diagonal shader");
+ return GL_INVALID_OPERATION;
+ }
+ if (!mCombinedProgram.isValid()) {
+ ALOGE("Invalid blur shader");
+ return GL_INVALID_OPERATION;
+ }
+
+ // First, we'll apply the vertical/diagonal pass, that receives the flattened background layers,
+ // and writes the output to two textures (vertical and diagonal.)
+ mVerticalDiagonalPassFbo.bind();
+ mVerticalDiagonalProgram.useProgram();
+
+ // set uniforms
+ auto width = mVerticalDiagonalPassFbo.getBufferWidth();
+ auto height = mVerticalDiagonalPassFbo.getBufferHeight();
+ auto radiusF = fmax(1.0f, radius * kFboScale);
+ glViewport(0, 0, width, height);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, mCompositionFbo.getTextureName());
+ glGenerateMipmap(GL_TEXTURE_2D);
+ glUniform1i(mVDTexture0Loc, 0);
+ glUniform2f(mVDSizeLoc, mDisplayWidth, mDisplayHeight);
+ glUniform1f(mVDRadiusLoc, radiusF);
+ glUniform1i(mVDNumSamplesLoc, kNumSamples);
+ mEngine.checkErrors("Setting vertical-diagonal pass uniforms");
+
+ drawMesh(mVDUvLoc, mVDPosLoc);
+
+ // Now we'll combine the multi render pass into a blurred image
+ mBlurredFbo.bind();
+ mCombinedProgram.useProgram();
+
+ // set uniforms
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, mVerticalDiagonalPassFbo.getTextureName());
+ glUniform1i(mCTexture0Loc, 0);
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, mVerticalDiagonalPassFbo.getSecondaryTextureName());
+ glUniform1i(mCTexture1Loc, 1);
+ glUniform2f(mCSizeLoc, mDisplayWidth, mDisplayHeight);
+ glUniform1f(mCRadiusLoc, radiusF);
+ glUniform1i(mCNumSamplesLoc, kNumSamples);
+ mEngine.checkErrors("Setting vertical pass uniforms");
+
+ drawMesh(mCUvLoc, mCPosLoc);
+
+ // reset active texture
+ mBlurredFbo.unbind();
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ // unbind program
+ glUseProgram(0);
+
+ return NO_ERROR;
+}
+
+string LensBlurFilter::getFragmentShader(bool forComposition) const {
+ string shader = "#version 310 es\n#define DIRECTION ";
+ shader += (forComposition ? "1" : "0");
+ shader += R"SHADER(
+ precision lowp float;
+
+ #define PI 3.14159265359
+
+ uniform sampler2D uTexture0;
+ uniform vec2 uSize;
+ uniform float uRadius;
+ uniform int uNumSamples;
+
+ mediump in vec2 vUV;
+
+ #if DIRECTION == 0
+ layout(location = 0) out vec4 fragColor0;
+ layout(location = 1) out vec4 fragColor1;
+ #else
+ uniform sampler2D uTexture1;
+ out vec4 fragColor;
+ #endif
+
+ const vec2 verticalMult = vec2(cos(PI / 2.0), sin(PI / 2.0));
+ const vec2 diagonalMult = vec2(cos(-PI / 6.0), sin(-PI / 6.0));
+ const vec2 diagonal2Mult = vec2(cos(-5.0 * PI / 6.0), sin(-5.0 * PI / 6.0));
+
+ vec3 blur(const sampler2D tex, vec2 uv, const vec2 direction, float radius,
+ int samples, float intensity) {
+ vec3 finalColor = vec3(0.0);
+ uv += direction * 0.5;
+
+ for (int i = 0; i < samples; i++){
+ float delta = radius * float(i) / float(samples);
+ vec3 color = texture(tex, uv + direction * delta).rgb;
+ color.rgb *= intensity;
+ finalColor += color;
+ }
+
+ return finalColor / float(samples);
+ }
+
+ vec3 blur(const sampler2D tex, vec2 uv, const vec2 direction, float radius,
+ int samples) {
+ return blur(tex, uv, direction, radius, samples, 1.0);
+ }
+
+ vec4[2] verticalDiagonalLensBlur (vec2 uv, sampler2D texture, vec2 resolution,
+ float radius, int samples) {
+ // Vertical Blur
+ vec2 blurDirV = 1.0 / resolution.xy * verticalMult;
+ vec3 colorV = blur(texture, uv, blurDirV, radius, samples);
+
+ // Diagonal Blur
+ vec2 blurDirD = 1.0 / resolution.xy * diagonalMult;
+ vec3 colorD = blur(texture, uv, blurDirD, radius, samples);
+
+ vec4 composed[2];
+ composed[0] = vec4(colorV, 1.0);
+ // added * 0.5, to remap
+ composed[1] = vec4((colorD + colorV) * 0.5, 1.0);
+
+ return composed;
+ }
+
+ vec4 rhombiLensBlur (vec2 uv, sampler2D texture0, sampler2D texture1, vec2 resolution,
+ float radius, int samples) {
+ vec2 blurDirection1 = 1.0 / resolution.xy * diagonalMult;
+ vec3 color1 = blur(texture0, uv, blurDirection1, radius, samples);
+
+ vec2 blurDirection2 = 1.0 / resolution.xy * diagonal2Mult;
+ vec3 color2 = blur(texture1, uv, blurDirection2, radius, samples, 2.0);
+
+ return vec4((color1 + color2) * 0.33, 1.0);
+ }
+
+ void main() {
+ #if DIRECTION == 0
+ // First pass: outputs two textures
+ vec4 colorOut[] = verticalDiagonalLensBlur(vUV, uTexture0, uSize, uRadius, uNumSamples);
+ fragColor0 = colorOut[0];
+ fragColor1 = colorOut[1];
+ #else
+ // Second pass: combines both textures into a blurred one.
+ fragColor = rhombiLensBlur(vUV, uTexture0, uTexture1, uSize, uRadius, uNumSamples);
+ #endif
+ }
+
+ )SHADER";
+ return shader;
+}
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/gl/filters/LensBlurFilter.h b/libs/renderengine/gl/filters/LensBlurFilter.h
new file mode 100644
index 0000000..8543f0d
--- /dev/null
+++ b/libs/renderengine/gl/filters/LensBlurFilter.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <ui/GraphicTypes.h>
+#include "../GLESRenderEngine.h"
+#include "../GLFramebuffer.h"
+#include "BlurFilter.h"
+#include "GenericProgram.h"
+
+using namespace std;
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+class LensBlurFilter : public BlurFilter {
+public:
+ explicit LensBlurFilter(GLESRenderEngine& engine);
+ status_t prepare(uint32_t radius) override;
+ void allocateTextures() override;
+
+private:
+ string getFragmentShader(bool forComposition) const;
+
+ // Intermediate render pass
+ GLFramebuffer mVerticalDiagonalPassFbo;
+
+ // Vertical/diagonal pass and its uniforms
+ GenericProgram mVerticalDiagonalProgram;
+ GLuint mVDPosLoc;
+ GLuint mVDUvLoc;
+ GLuint mVDTexture0Loc;
+ GLuint mVDSizeLoc;
+ GLuint mVDRadiusLoc;
+ GLuint mVDNumSamplesLoc;
+
+ // Blur composition pass and its uniforms
+ GenericProgram mCombinedProgram;
+ GLuint mCPosLoc;
+ GLuint mCUvLoc;
+ GLuint mCTexture0Loc;
+ GLuint mCTexture1Loc;
+ GLuint mCSizeLoc;
+ GLuint mCRadiusLoc;
+ GLuint mCNumSamplesLoc;
+};
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
\ No newline at end of file
diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
index 5aa3f3b..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.
@@ -149,8 +149,12 @@
bool disableBlending = false;
ShadowSettings shadow;
+
+ 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 &&
@@ -182,7 +186,8 @@
return lhs.geometry == rhs.geometry && lhs.source == rhs.source && lhs.alpha == rhs.alpha &&
lhs.sourceDataspace == rhs.sourceDataspace &&
lhs.colorTransform == rhs.colorTransform &&
- lhs.disableBlending == rhs.disableBlending && lhs.shadow == rhs.shadow;
+ lhs.disableBlending == rhs.disableBlending && lhs.shadow == rhs.shadow &&
+ lhs.backgroundBlurRadius == rhs.backgroundBlurRadius;
}
// Defining PrintTo helps with Google Tests.
@@ -243,6 +248,7 @@
PrintTo(settings.sourceDataspace, os);
*os << "\n .colorTransform = " << settings.colorTransform;
*os << "\n .disableBlending = " << settings.disableBlending;
+ *os << "\n .backgroundBlurRadius = " << settings.backgroundBlurRadius;
*os << "\n .shadow = ";
PrintTo(settings.shadow, os);
*os << "\n}";
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 4db5c57..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;
@@ -174,6 +174,7 @@
bool useColorManagement;
bool enableProtectedContext;
bool precacheToneMapperShaderOnly;
+ bool supportsBackgroundBlur;
RenderEngine::ContextPriority contextPriority;
struct Builder;
@@ -186,12 +187,14 @@
bool _useColorManagement,
bool _enableProtectedContext,
bool _precacheToneMapperShaderOnly,
+ bool _supportsBackgroundBlur,
RenderEngine::ContextPriority _contextPriority)
: pixelFormat(_pixelFormat)
, imageCacheSize(_imageCacheSize)
, useColorManagement(_useColorManagement)
, enableProtectedContext(_enableProtectedContext)
, precacheToneMapperShaderOnly(_precacheToneMapperShaderOnly)
+ , supportsBackgroundBlur(_supportsBackgroundBlur)
, contextPriority(_contextPriority) {}
RenderEngineCreationArgs() = delete;
};
@@ -219,13 +222,18 @@
this->precacheToneMapperShaderOnly = precacheToneMapperShaderOnly;
return *this;
}
+ Builder& setSupportsBackgroundBlur(bool supportsBackgroundBlur) {
+ this->supportsBackgroundBlur = supportsBackgroundBlur;
+ return *this;
+ }
Builder& setContextPriority(RenderEngine::ContextPriority contextPriority) {
this->contextPriority = contextPriority;
return *this;
}
RenderEngineCreationArgs build() const {
return RenderEngineCreationArgs(pixelFormat, imageCacheSize, useColorManagement,
- enableProtectedContext, precacheToneMapperShaderOnly, contextPriority);
+ enableProtectedContext, precacheToneMapperShaderOnly,
+ supportsBackgroundBlur, contextPriority);
}
private:
@@ -235,6 +243,7 @@
bool useColorManagement = true;
bool enableProtectedContext = false;
bool precacheToneMapperShaderOnly = false;
+ bool supportsBackgroundBlur = false;
RenderEngine::ContextPriority contextPriority = RenderEngine::ContextPriority::MEDIUM;
};
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 ba5a3f5..afcbc50 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -14,11 +14,16 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <chrono>
#include <condition_variable>
#include <fstream>
#include <gtest/gtest.h>
+#include <cutils/properties.h>
#include <renderengine/RenderEngine.h>
#include <sync/sync.h>
#include <ui/PixelFormat.h>
@@ -40,6 +45,7 @@
.setUseColorManagerment(false)
.setEnableProtectedContext(false)
.setPrecacheToneMapperShaderOnly(false)
+ .setSupportsBackgroundBlur(true)
.setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM)
.build());
}
@@ -243,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);
@@ -263,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);
@@ -324,6 +331,9 @@
void fillBufferWithRoundedCorners();
template <typename SourceVariant>
+ void fillBufferAndBlurBackground();
+
+ template <typename SourceVariant>
void overlayCorners();
void fillRedBufferTextureTransform();
@@ -431,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);
}
@@ -473,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);
}
@@ -506,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);
@@ -526,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);
}
@@ -607,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();
@@ -617,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);
}
@@ -638,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();
@@ -654,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);
}
@@ -671,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();
@@ -680,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);
}
@@ -702,12 +712,57 @@
}
template <typename SourceVariant>
+void RenderEngineTest::fillBufferAndBlurBackground() {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.surface_flinger.supports_background_blur", value, "0");
+ if (!atoi(value)) {
+ // This device doesn't support blurs, no-op.
+ return;
+ }
+
+ auto blurRadius = 50;
+ auto center = DEFAULT_DISPLAY_WIDTH / 2;
+
+ renderengine::DisplaySettings settings;
+ settings.physicalDisplay = fullscreenRect();
+ settings.clip = fullscreenRect();
+
+ 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);
+
+ 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);
+
+ renderengine::LayerSettings blurLayer;
+ blurLayer.geometry.boundaries = fullscreenRect().toFloatRect();
+ blurLayer.backgroundBlurRadius = blurRadius;
+ blurLayer.alpha = 0;
+ layers.push_back(&blurLayer);
+
+ invokeDraw(settings, layers, mBuffer);
+
+ expectBufferColor(Rect(center - 1, center - 5, center, center + 5), 150, 150, 0, 255,
+ 50 /* tolerance */);
+ expectBufferColor(Rect(center, center - 5, center + 1, center + 5), 150, 150, 0, 255,
+ 50 /* tolerance */);
+}
+
+template <typename SourceVariant>
void RenderEngineTest::overlayCorners() {
renderengine::DisplaySettings settings;
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
- std::vector<renderengine::LayerSettings> layersFirst;
+ std::vector<const renderengine::LayerSettings*> layersFirst;
renderengine::LayerSettings layerOne;
layerOne.geometry.boundaries =
@@ -715,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,
@@ -730,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);
@@ -744,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
@@ -779,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);
}
@@ -795,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);
@@ -818,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);
}
@@ -834,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);
@@ -857,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);
}
@@ -874,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);
}
@@ -898,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;
@@ -906,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);
}
@@ -930,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);
@@ -946,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);
@@ -965,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);
@@ -1028,6 +1083,10 @@
fillBufferWithRoundedCorners<ColorSourceVariant>();
}
+TEST_F(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_colorSource) {
+ fillBufferAndBlurBackground<ColorSourceVariant>();
+}
+
TEST_F(RenderEngineTest, drawLayers_overlayCorners_colorSource) {
overlayCorners<ColorSourceVariant>();
}
@@ -1080,6 +1139,10 @@
fillBufferWithRoundedCorners<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
+TEST_F(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_opaqueBufferSource) {
+ fillBufferAndBlurBackground<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
TEST_F(RenderEngineTest, drawLayers_overlayCorners_opaqueBufferSource) {
overlayCorners<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
@@ -1132,6 +1195,10 @@
fillBufferWithRoundedCorners<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
+TEST_F(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_bufferSource) {
+ fillBufferAndBlurBackground<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
TEST_F(RenderEngineTest, drawLayers_overlayCorners_bufferSource) {
overlayCorners<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
@@ -1157,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));
@@ -1339,3 +1406,6 @@
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/libs/sensor/Sensor.cpp b/libs/sensor/Sensor.cpp
index abc9103..9d817ae 100644
--- a/libs/sensor/Sensor.cpp
+++ b/libs/sensor/Sensor.cpp
@@ -268,6 +268,10 @@
mStringType = SENSOR_STRING_TYPE_ACCELEROMETER_UNCALIBRATED;
mFlags |= SENSOR_FLAG_CONTINUOUS_MODE;
break;
+ case SENSOR_TYPE_HINGE_ANGLE:
+ mStringType = SENSOR_STRING_TYPE_HINGE_ANGLE;
+ mFlags |= SENSOR_FLAG_ON_CHANGE_MODE;
+ break;
default:
// Only pipe the stringType, requiredPermission and flags for custom sensors.
if (halVersion > SENSORS_DEVICE_API_VERSION_1_0 && hwSensor.stringType) {
diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp
index bf8b9f7..a4a5d13 100644
--- a/libs/sensor/SensorManager.cpp
+++ b/libs/sensor/SensorManager.cpp
@@ -209,7 +209,7 @@
type == SENSOR_TYPE_TILT_DETECTOR || type == SENSOR_TYPE_WAKE_GESTURE ||
type == SENSOR_TYPE_GLANCE_GESTURE || type == SENSOR_TYPE_PICK_UP_GESTURE ||
type == SENSOR_TYPE_WRIST_TILT_GESTURE ||
- type == SENSOR_TYPE_LOW_LATENCY_OFFBODY_DETECT) {
+ type == SENSOR_TYPE_LOW_LATENCY_OFFBODY_DETECT || type == SENSOR_TYPE_HINGE_ANGLE) {
wakeUpSensor = true;
}
// For now we just return the first sensor of that type we find.
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 043f2ca..ba6255d 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -32,12 +32,6 @@
sanitize: {
integer_overflow: true,
misc_undefined: ["bounds"],
- diag: {
- misc_undefined: ["bounds"],
- no_recover: [
- "bounds",
- ],
- },
},
srcs: [
diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp
index 04493f0..abc64bd 100644
--- a/libs/vr/libvrflinger/Android.bp
+++ b/libs/vr/libvrflinger/Android.bp
@@ -66,6 +66,7 @@
"android.hardware.graphics.composer@2.1-command-buffer",
"android.hardware.graphics.composer@2.2-command-buffer",
"android.hardware.graphics.composer@2.3-command-buffer",
+ "android.hardware.graphics.composer@2.4-command-buffer",
"libdvr_headers",
"libsurfaceflinger_headers",
]
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 51878e9..e19802b 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -25,6 +25,7 @@
#include <dlfcn.h>
#include <android/dlext.h>
+#include <cutils/properties.h>
#include <log/log.h>
#include <utils/Timers.h>
@@ -205,7 +206,6 @@
}
cnx->systemDriverUnloaded = true;
- cnx->loadedDriverType = egl_connection_t::GLES_NO_DRIVER;
}
void* Loader::open(egl_connection_t* cnx)
@@ -228,7 +228,6 @@
} else {
cnx->shouldUseAngle = false;
}
- cnx->loadedDriverType = egl_connection_t::GLES_NO_DRIVER;
// Firstly, try to load ANGLE driver.
driver_t* hnd = attempt_to_load_angle(cnx);
@@ -238,7 +237,6 @@
}
bool failToLoadFromDriverSuffixProperty = false;
- cnx->systemDriverUseExactName = true;
if (!hnd) {
// If updated driver apk is set but fail to load, abort here.
if (android::GraphicsEnv::getInstance().getDriverNamespace()) {
@@ -250,19 +248,16 @@
// i.e.:
// libGLES_${prop}.so, or:
// libEGL_${prop}.so, libGLESv1_CM_${prop}.so, libGLESv2_${prop}.so
+ char prop[PROPERTY_VALUE_MAX + 1];
for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
- if (property_get(key, cnx->systemDriverProperty, nullptr) <= 0) {
+ if (property_get(key, prop, nullptr) <= 0) {
continue;
}
- hnd = attempt_to_load_system_driver(cnx, cnx->systemDriverProperty,
- cnx->systemDriverUseExactName);
+ hnd = attempt_to_load_system_driver(cnx, prop, true);
if (hnd) {
- cnx->systemDriverUseProperty = true;
break;
- } else {
- if (strcmp(key, DRIVER_SUFFIX_PROPERTY) == 0) {
- failToLoadFromDriverSuffixProperty = true;
- }
+ } else if (strcmp(key, DRIVER_SUFFIX_PROPERTY) == 0) {
+ failToLoadFromDriverSuffixProperty = true;
}
}
}
@@ -273,12 +268,11 @@
// i.e.:
// libGLES.so, or:
// libEGL.so, libGLESv1_CM.so, libGLESv2.so
- hnd = attempt_to_load_system_driver(cnx, nullptr, cnx->systemDriverUseExactName);
+ hnd = attempt_to_load_system_driver(cnx, nullptr, true);
}
if (!hnd && !failToLoadFromDriverSuffixProperty) {
- cnx->systemDriverUseExactName = false;
- hnd = attempt_to_load_system_driver(cnx, nullptr, cnx->systemDriverUseExactName);
+ hnd = attempt_to_load_system_driver(cnx, nullptr, false);
}
if (!hnd) {
@@ -293,11 +287,14 @@
if (!cnx->libEgl) {
cnx->libEgl = load_wrapper(EGL_WRAPPER_DIR "/libEGL.so");
}
+ if (!cnx->libGles1) {
+ cnx->libGles1 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv1_CM.so");
+ }
if (!cnx->libGles2) {
cnx->libGles2 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv2.so");
}
- if (!cnx->libEgl || !cnx->libGles2) {
+ if (!cnx->libEgl || !cnx->libGles2 || !cnx->libGles1) {
android::GraphicsEnv::getInstance().setDriverLoaded(android::GpuStatsInfo::Api::API_GL,
false, systemTime() - openTime);
}
@@ -305,7 +302,8 @@
LOG_ALWAYS_FATAL_IF(!cnx->libEgl,
"couldn't load system EGL wrapper libraries");
- LOG_ALWAYS_FATAL_IF(!cnx->libGles2, "couldn't load system OpenGL ESv2+ wrapper libraries");
+ LOG_ALWAYS_FATAL_IF(!cnx->libGles2 || !cnx->libGles1,
+ "couldn't load system OpenGL ES wrapper libraries");
android::GraphicsEnv::getInstance().setDriverLoaded(android::GpuStatsInfo::Api::API_GL, true,
systemTime() - openTime);
@@ -321,7 +319,7 @@
cnx->shouldUseAngle = false;
cnx->angleDecided = false;
- cnx->loadedDriverType = egl_connection_t::GLES_NO_DRIVER;
+ cnx->useAngle = false;
if (cnx->vendorEGL) {
dlclose(cnx->vendorEGL);
@@ -526,6 +524,7 @@
if (so) {
ALOGV("Loaded ANGLE %s library for '%s' (instead of native)", kind,
android::GraphicsEnv::getInstance().getAngleAppName().c_str());
+ cnx->useAngle = true;
char prop[PROPERTY_VALUE_MAX];
@@ -568,6 +567,7 @@
} else {
ALOGV("Loaded native %s library for '%s' (instead of ANGLE)", kind,
android::GraphicsEnv::getInstance().getAngleAppName().c_str());
+ cnx->useAngle = false;
}
cnx->angleDecided = true;
@@ -597,7 +597,6 @@
Loader::driver_t* Loader::attempt_to_load_angle(egl_connection_t* cnx) {
ATRACE_CALL();
- assert(cnx->loadedDriverType == egl_connection_t::GLES_NO_DRIVER);
android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace();
if (!ns) {
return nullptr;
@@ -612,17 +611,19 @@
initialize_api(dso, cnx, EGL);
hnd = new driver_t(dso);
+ dso = load_angle("GLESv1_CM", ns, cnx);
+ initialize_api(dso, cnx, GLESv1_CM);
+ hnd->set(dso, GLESv1_CM);
+
dso = load_angle("GLESv2", ns, cnx);
initialize_api(dso, cnx, GLESv2);
hnd->set(dso, GLESv2);
- cnx->loadedDriverType = egl_connection_t::GLES_ANGLE_STANDALONE_DRIVER;
}
return hnd;
}
Loader::driver_t* Loader::attempt_to_load_updated_driver(egl_connection_t* cnx) {
ATRACE_CALL();
- assert(cnx->loadedDriverType == egl_connection_t::GLES_NO_DRIVER);
#ifndef __ANDROID_VNDK__
android_namespace_t* ns = android::GraphicsEnv::getInstance().getDriverNamespace();
if (!ns) {
@@ -634,9 +635,8 @@
driver_t* hnd = nullptr;
void* dso = load_updated_driver("GLES", ns);
if (dso) {
- initialize_api(dso, cnx, EGL | GLESv2);
+ initialize_api(dso, cnx, EGL | GLESv1_CM | GLESv2);
hnd = new driver_t(dso);
- if (hnd) cnx->loadedDriverType = egl_connection_t::GLES_UPDATED_COMBO_DRIVER;
return hnd;
}
@@ -645,10 +645,13 @@
initialize_api(dso, cnx, EGL);
hnd = new driver_t(dso);
+ dso = load_updated_driver("GLESv1_CM", ns);
+ initialize_api(dso, cnx, GLESv1_CM);
+ hnd->set(dso, GLESv1_CM);
+
dso = load_updated_driver("GLESv2", ns);
initialize_api(dso, cnx, GLESv2);
hnd->set(dso, GLESv2);
- cnx->loadedDriverType = egl_connection_t::GLES_UPDATED_STANDALONE_DRIVER;
}
return hnd;
#else
@@ -659,94 +662,30 @@
Loader::driver_t* Loader::attempt_to_load_system_driver(egl_connection_t* cnx, const char* suffix,
const bool exact) {
ATRACE_CALL();
- assert(cnx->loadedDriverType == egl_connection_t::GLES_NO_DRIVER);
android::GraphicsEnv::getInstance().setDriverToLoad(android::GpuStatsInfo::Driver::GL);
driver_t* hnd = nullptr;
void* dso = load_system_driver("GLES", suffix, exact);
if (dso) {
- initialize_api(dso, cnx, EGL | GLESv2);
+ initialize_api(dso, cnx, EGL | GLESv1_CM | GLESv2);
hnd = new driver_t(dso);
- if (hnd) cnx->loadedDriverType = egl_connection_t::GLES_SYSTEM_COMBO_DRIVER;
return hnd;
}
-
dso = load_system_driver("EGL", suffix, exact);
if (dso) {
initialize_api(dso, cnx, EGL);
hnd = new driver_t(dso);
+ dso = load_system_driver("GLESv1_CM", suffix, exact);
+ initialize_api(dso, cnx, GLESv1_CM);
+ hnd->set(dso, GLESv1_CM);
+
dso = load_system_driver("GLESv2", suffix, exact);
initialize_api(dso, cnx, GLESv2);
hnd->set(dso, GLESv2);
- cnx->loadedDriverType = egl_connection_t::GLES_SYSTEM_STANDALONE_DRIVER;
}
return hnd;
}
-bool Loader::load_glesv1_driver(egl_connection_t* cnx) {
- ATRACE_CALL();
- void* dso = nullptr;
-
- driver_t* hnd = (driver_t*)cnx->dso;
- // EGL driver must have been loaded. if not, something went wrong.
- if (!hnd || cnx->loadedDriverType == egl_connection_t::GLES_NO_DRIVER) {
- return false;
- }
-
- if (cnx->libGles1) return EGL_TRUE;
-
- // If there is a GLES driver, use that first
- switch (cnx->loadedDriverType) {
- case egl_connection_t::GLES_SYSTEM_COMBO_DRIVER:
- case egl_connection_t::GLES_UPDATED_COMBO_DRIVER: {
- dso = hnd->dso[0];
- initialize_api(dso, cnx, GLESv1_CM);
- break;
- }
- case egl_connection_t::GLES_ANGLE_STANDALONE_DRIVER: {
- android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace();
- dso = load_angle("GLESv1_CM", ns, cnx);
- if (dso) {
- initialize_api(dso, cnx, GLESv1_CM);
- hnd->set(dso, GLESv1_CM);
- }
- break;
- }
- case egl_connection_t::GLES_UPDATED_STANDALONE_DRIVER: {
- android_namespace_t* ns = android::GraphicsEnv::getInstance().getDriverNamespace();
- void* dso = load_updated_driver("GLESv1_CM", ns);
- if (dso) {
- initialize_api(dso, cnx, GLESv1_CM);
- hnd->set(dso, GLESv1_CM);
- }
- break;
- }
- case egl_connection_t::GLES_SYSTEM_STANDALONE_DRIVER: {
- dso = load_system_driver("GLESv1_CM",
- cnx->systemDriverUseProperty ? cnx->systemDriverProperty
- : nullptr,
- cnx->systemDriverUseExactName);
- if (dso) {
- initialize_api(dso, cnx, GLESv1_CM);
- hnd->set(dso, GLESv1_CM);
- }
- break;
- }
- default: {
- ALOGE("Bad loadedDriverType (%d)", cnx->loadedDriverType);
- break;
- }
- }
-
- if (!cnx->libGles1) {
- cnx->libGles1 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv1_CM.so");
- }
-
- LOG_ALWAYS_FATAL_IF(!cnx->libGles1, "couldn't load system OpenGL ES V1 wrapper libraries");
-
- return dso ? true : false;
-}
-
void Loader::initialize_api(void* dso, egl_connection_t* cnx, uint32_t mask) {
if (mask & EGL) {
getProcAddress = (getProcAddressType)dlsym(dso, "eglGetProcAddress");
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
index 4199753..6f31ab4 100644
--- a/opengl/libs/EGL/Loader.h
+++ b/opengl/libs/EGL/Loader.h
@@ -53,8 +53,6 @@
void* open(egl_connection_t* cnx);
void close(egl_connection_t* cnx);
- bool load_glesv1_driver(egl_connection_t* cnx);
-
private:
Loader();
driver_t* attempt_to_load_angle(egl_connection_t* cnx);
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 2e183b3..0581708 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -198,14 +198,6 @@
return cnx->dso ? EGL_TRUE : EGL_FALSE;
}
-static EGLBoolean egl_init_glesv1_drivers_locked() {
- // get our driver loader
- Loader& loader(Loader::getInstance());
-
- // dynamically load our GLESV1 implementation
- egl_connection_t* cnx = &gEGLImpl;
- return loader.load_glesv1_driver(cnx);
-}
// this mutex protects driver load logic as a critical section since it accesses to global variable
// like gEGLImpl
@@ -219,14 +211,6 @@
return res;
}
-EGLBoolean egl_init_glesv1_drivers() {
- EGLBoolean res;
- pthread_mutex_lock(&sInitDriverMutex);
- res = egl_init_glesv1_drivers_locked();
- pthread_mutex_unlock(&sInitDriverMutex);
- return res;
-}
-
static pthread_mutex_t sLogPrintMutex = PTHREAD_MUTEX_INITIALIZER;
static std::chrono::steady_clock::time_point sLogPrintTime;
static constexpr std::chrono::seconds DURATION(1);
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 3b19b32..67d69b4 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -220,7 +220,7 @@
if (cnx->dso) {
EGLDisplay dpy = EGL_NO_DISPLAY;
- if (cnx->loadedDriverType == egl_connection_t::GLES_ANGLE_STANDALONE_DRIVER) {
+ if (cnx->useAngle) {
EGLint error;
dpy = getPlatformDisplayAngle(display, cnx, attrib_list, &error);
if (error != EGL_NONE) {
@@ -464,7 +464,7 @@
egl_connection_t* const cnx = &gEGLImpl;
if (cnx->dso && disp.state == egl_display_t::INITIALIZED) {
// If we're using ANGLE reset any custom DisplayPlatform
- if (cnx->loadedDriverType == egl_connection_t::GLES_ANGLE_STANDALONE_DRIVER) {
+ if (cnx->useAngle) {
angle::resetAnglePlatform(disp.dpy);
}
if (cnx->egl.eglTerminate(disp.dpy) == EGL_FALSE) {
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index e2bc5c6..c8840f9 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -277,7 +277,6 @@
extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
extern EGLBoolean egl_init_drivers();
-extern EGLBoolean egl_init_glesv1_drivers();
extern const __eglMustCastToProperFunctionPointerType gExtensionForwarders[MAX_NUMBER_OF_GL_EXTENSIONS];
extern gl_hooks_t gHooksTrace;
@@ -957,42 +956,41 @@
egl_context_t* const c = get_context(share_list);
share_list = c->context;
}
-
- // figure out if it's a GLESv1 or GLESv2
- int gles_version_idx = egl_connection_t::GLESv1_INDEX;
- if (attrib_list) {
- const EGLint* ptr = attrib_list; // so that we don't modify attrib_list
- while (*ptr != EGL_NONE) {
- GLint attr = *ptr++;
- GLint value = *ptr++;
- if (attr == EGL_CONTEXT_CLIENT_VERSION) {
- if (value == 1) {
- gles_version_idx = egl_connection_t::GLESv1_INDEX;
- } else if (value == 2 || value == 3) {
- gles_version_idx = egl_connection_t::GLESv2_INDEX;
- }
- } else if (attr == EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR &&
- cnx->driverVersion < EGL_MAKE_VERSION(1, 5, 0)) {
- // b/111083885 - If we are presenting EGL 1.4 interface to apps
- // error out on robust access attributes that are invalid
- // in EGL 1.4 as the driver may be fine with them but dEQP expects
- // tests to fail according to spec.
+ // b/111083885 - If we are presenting EGL 1.4 interface to apps
+ // error out on robust access attributes that are invalid
+ // in EGL 1.4 as the driver may be fine with them but dEQP expects
+ // tests to fail according to spec.
+ if (attrib_list && (cnx->driverVersion < EGL_MAKE_VERSION(1, 5, 0))) {
+ const EGLint* attrib_ptr = attrib_list;
+ while (*attrib_ptr != EGL_NONE) {
+ GLint attr = *attrib_ptr++;
+ GLint value = *attrib_ptr++;
+ if (attr == EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR) {
+ // We are GL ES context with EGL 1.4, this is an invalid
+ // attribute
return setError(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
}
- }
+ };
}
-
- // GLESV1 driver is lazily loaded and initialized
- if (gles_version_idx == egl_connection_t::GLESv1_INDEX) {
- android::GraphicsEnv::getInstance().setTargetStats(
- android::GpuStatsInfo::Stats::GLES_1_IN_USE);
- if (!egl_init_glesv1_drivers()) return EGL_NO_CONTEXT;
- }
-
EGLContext context = cnx->egl.eglCreateContext(
dp->disp.dpy, config, share_list, attrib_list);
if (context != EGL_NO_CONTEXT) {
- egl_context_t* c = new egl_context_t(dpy, context, config, cnx, gles_version_idx);
+ // figure out if it's a GLESv1 or GLESv2
+ int version = egl_connection_t::GLESv1_INDEX;
+ if (attrib_list) {
+ while (*attrib_list != EGL_NONE) {
+ GLint attr = *attrib_list++;
+ GLint value = *attrib_list++;
+ if (attr == EGL_CONTEXT_CLIENT_VERSION && (value == 2 || value == 3)) {
+ version = egl_connection_t::GLESv2_INDEX;
+ }
+ };
+ }
+ if (version == egl_connection_t::GLESv1_INDEX) {
+ android::GraphicsEnv::getInstance().setTargetStats(
+ android::GpuStatsInfo::Stats::GLES_1_IN_USE);
+ }
+ egl_context_t* c = new egl_context_t(dpy, context, config, cnx, version);
return c;
}
}
diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h
index 4e9d7d0..7bb9b59 100644
--- a/opengl/libs/EGL/egldefs.h
+++ b/opengl/libs/EGL/egldefs.h
@@ -17,12 +17,11 @@
#ifndef ANDROID_EGLDEFS_H
#define ANDROID_EGLDEFS_H
-#include <cutils/properties.h>
-#include <log/log.h>
-
#include "../hooks.h"
#include "egl_platform_entries.h"
+#include <log/log.h>
+
#define VERSION_MAJOR 1
#define VERSION_MINOR 4
#define EGL_MAKE_VERSION(major, minor, patch) (((major) << 22) | ((minor) << 12) | (patch))
@@ -45,15 +44,6 @@
GLESv2_INDEX = 1
};
- enum {
- GLES_NO_DRIVER = 0, // no driver is loaded
- GLES_SYSTEM_COMBO_DRIVER = 1, // GLES combo driver in system folder is loaded
- GLES_SYSTEM_STANDALONE_DRIVER = 2, // standalone system drivers are loaded
- GLES_ANGLE_STANDALONE_DRIVER = 3, // ANGLE (always standalone) drivers are loaded.
- GLES_UPDATED_COMBO_DRIVER = 4, // GLES combo driver in updated driver folder is loaded
- GLES_UPDATED_STANDALONE_DRIVER = 5, // standalone drivers in updated driver folder are loaded
- };
-
inline egl_connection_t() : dso(nullptr),
libEgl(nullptr),
libGles1(nullptr),
@@ -93,12 +83,9 @@
bool systemDriverUnloaded;
bool shouldUseAngle; // Should we attempt to load ANGLE
bool angleDecided; // Have we tried to load ANGLE
+ bool useAngle; // Was ANGLE successfully loaded
EGLint angleBackend;
- int loadedDriverType;
void* vendorEGL;
- bool systemDriverUseExactName;
- bool systemDriverUseProperty;
- char systemDriverProperty[PROPERTY_VALUE_MAX + 1];
};
// clang-format on
diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp
index 55a0c0a..be4a462 100644
--- a/services/gpuservice/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -28,12 +28,7 @@
#include <utils/String8.h>
#include <utils/Trace.h>
-#include <array>
-#include <fstream>
-#include <sstream>
-#include <sys/types.h>
#include <vkjson.h>
-#include <unistd.h>
#include "gpustats/GpuStats.h"
@@ -45,7 +40,6 @@
status_t cmdHelp(int out);
status_t cmdVkjson(int out, int err);
void dumpGameDriverInfo(std::string* result);
-void dumpMemoryInfo(std::string* result, const GpuMemoryMap& memories, uint32_t pid);
} // namespace
const String16 sDump("android.permission.DUMP");
@@ -78,147 +72,6 @@
mGpuStats->insertTargetStats(appPackageName, driverVersionCode, stats, value);
}
-bool isExpectedFormat(const char* str) {
- // Should match in order:
- // gpuaddr useraddr size id flags type usage sglen mapsize eglsrf eglimg
- std::istringstream iss;
- iss.str(str);
-
- std::string word;
- iss >> word;
- if (word != "gpuaddr") { return false; }
- iss >> word;
- if (word != "useraddr") { return false; }
- iss >> word;
- if (word != "size") { return false; }
- iss >> word;
- if (word != "id") { return false; }
- iss >> word;
- if (word != "flags") { return false; }
- iss >> word;
- if (word != "type") { return false; }
- iss >> word;
- if (word != "usage") { return false; }
- iss >> word;
- if (word != "sglen") { return false; }
- iss >> word;
- if (word != "mapsize") { return false; }
- iss >> word;
- if (word != "eglsrf") { return false; }
- iss >> word;
- if (word != "eglimg") { return false; }
- return true;
-}
-
-
-// Queries gpu memory via Qualcomm's /d/kgsl/proc/*/mem interface.
-status_t GpuService::getQCommGpuMemoryInfo(GpuMemoryMap* memories, std::string* result, int32_t dumpPid) const {
- const std::string kDirectoryPath = "/d/kgsl/proc";
- DIR* directory = opendir(kDirectoryPath.c_str());
- if (!directory) { return PERMISSION_DENIED; }
-
- // File Format:
- // gpuaddr useraddr size id flags type usage sglen mapsize eglsrf eglimg
- // 0000000000000000 0000000000000000 8359936 23 --w--pY-- gpumem VK/others( 38) 0 0 0 0
- // 0000000000000000 0000000000000000 16293888 24 --wL--N-- ion surface 41 0 0 1
-
- const bool dumpAll = dumpPid == 0;
- static constexpr size_t kMaxLineLength = 1024;
- static char line[kMaxLineLength];
- while(dirent* subdir = readdir(directory)) {
- // Skip "." and ".." in directory.
- if (strcmp(subdir->d_name, ".") == 0 || strcmp(subdir->d_name, "..") == 0 ) { continue; }
-
- std::string pid_str(subdir->d_name);
- const uint32_t pid(stoi(pid_str));
-
- if (!dumpAll && dumpPid != pid) {
- continue;
- }
-
- std::string filepath(kDirectoryPath + "/" + pid_str + "/mem");
- std::ifstream file(filepath);
-
- // Check first line
- file.getline(line, kMaxLineLength);
- if (!isExpectedFormat(line)) {
- continue;
- }
-
- if (result) {
- StringAppendF(result, "%d:\n%s\n", pid, line);
- }
-
- while( file.getline(line, kMaxLineLength) ) {
- if (result) {
- StringAppendF(result, "%s\n", line);
- }
-
- std::istringstream iss;
- iss.str(line);
-
- // Skip gpuaddr, useraddr.
- const char delimiter = ' ';
- iss >> std::ws;
- iss.ignore(kMaxLineLength, delimiter);
- iss >> std::ws;
- iss.ignore(kMaxLineLength, delimiter);
-
- // Get size.
- int64_t memsize;
- iss >> memsize;
-
- // Skip id, flags.
- iss >> std::ws;
- iss.ignore(kMaxLineLength, delimiter);
- iss >> std::ws;
- iss.ignore(kMaxLineLength, delimiter);
-
- // Get type, usage.
- std::string memtype;
- std::string usage;
- iss >> memtype >> usage;
-
- // Adjust for the space in VK/others( #)
- if (usage == "VK/others(") {
- std::string vkTypeEnd;
- iss >> vkTypeEnd;
- usage.append(vkTypeEnd);
- }
-
- // Skip sglen.
- iss >> std::ws;
- iss.ignore(kMaxLineLength, delimiter);
-
- // Get mapsize.
- int64_t mapsize;
- iss >> mapsize;
-
- if (memsize == 0 && mapsize == 0) {
- continue;
- }
-
- if (memtype == "gpumem") {
- (*memories)[pid][usage].gpuMemory += memsize;
- } else {
- (*memories)[pid][usage].ionMemory += memsize;
- }
-
- if (mapsize > 0) {
- (*memories)[pid][usage].mappedMemory += mapsize;
- }
- }
-
- if (result) {
- StringAppendF(result, "\n");
- }
- }
-
- closedir(directory);
-
- return OK;
-}
-
status_t GpuService::shellCommand(int /*in*/, int out, int err, std::vector<String16>& args) {
ATRACE_CALL();
@@ -248,9 +101,7 @@
bool dumpAll = true;
bool dumpDriverInfo = false;
bool dumpStats = false;
- bool dumpMemory = false;
size_t numArgs = args.size();
- int32_t pid = 0;
if (numArgs) {
dumpAll = false;
@@ -259,11 +110,6 @@
dumpStats = true;
} else if (args[index] == String16("--gpudriverinfo")) {
dumpDriverInfo = true;
- } else if (args[index] == String16("--gpumem")) {
- dumpMemory = true;
- } else if (args[index].startsWith(String16("--gpumem="))) {
- dumpMemory = true;
- pid = atoi(String8(&args[index][9]));
}
}
}
@@ -276,14 +122,6 @@
mGpuStats->dump(args, &result);
result.append("\n");
}
- if (dumpAll || dumpMemory) {
- GpuMemoryMap memories;
- // Currently only queries Qualcomm gpu memory. More will be added later.
- if (getQCommGpuMemoryInfo(&memories, &result, pid) == OK) {
- dumpMemoryInfo(&result, memories, pid);
- result.append("\n");
- }
- }
}
write(fd, result.c_str(), result.size());
@@ -335,34 +173,6 @@
StringAppendF(result, "Pre-release Game Driver: %s\n", preReleaseGameDriver);
}
-// Read and print all memory info for each process from /d/kgsl/proc/<pid>/mem.
-void dumpMemoryInfo(std::string* result, const GpuMemoryMap& memories, uint32_t pid) {
- if (!result) return;
-
- // Write results.
- StringAppendF(result, "GPU Memory Summary:\n");
- for(auto& mem : memories) {
- uint32_t process = mem.first;
- if (pid != 0 && pid != process) {
- continue;
- }
-
- StringAppendF(result, "%d:\n", process);
- for(auto& memStruct : mem.second) {
- StringAppendF(result, " %s", memStruct.first.c_str());
-
- if(memStruct.second.gpuMemory > 0)
- StringAppendF(result, ", GPU memory = %" PRId64, memStruct.second.gpuMemory);
- if(memStruct.second.mappedMemory > 0)
- StringAppendF(result, ", Mapped memory = %" PRId64, memStruct.second.mappedMemory);
- if(memStruct.second.ionMemory > 0)
- StringAppendF(result, ", Ion memory = %" PRId64, memStruct.second.ionMemory);
-
- StringAppendF(result, "\n");
- }
- }
-}
-
} // anonymous namespace
} // namespace android
diff --git a/services/inputflinger/InputReaderBase.cpp b/services/inputflinger/InputReaderBase.cpp
index 2d6f2c1..b2dadf8 100644
--- a/services/inputflinger/InputReaderBase.cpp
+++ b/services/inputflinger/InputReaderBase.cpp
@@ -125,6 +125,16 @@
return std::nullopt;
}
+std::optional<DisplayViewport> InputReaderConfiguration::getDisplayViewportById(
+ int32_t displayId) const {
+ for (const DisplayViewport& currentViewport : mDisplays) {
+ if (currentViewport.displayId == displayId) {
+ return std::make_optional(currentViewport);
+ }
+ }
+ return std::nullopt;
+}
+
void InputReaderConfiguration::setDisplayViewports(const std::vector<DisplayViewport>& viewports) {
mDisplays = viewports;
}
@@ -151,4 +161,4 @@
y = newY;
}
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 39b9595..14bcbf7 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -270,7 +270,7 @@
ALOG_ASSERT(eventEntry->type == EventEntry::Type::MOTION);
const MotionEntry& motionEntry = static_cast<const MotionEntry&>(*eventEntry);
- PointerCoords pointerCoords[MAX_POINTERS];
+ PointerCoords pointerCoords[motionEntry.pointerCount];
// Use the first pointer information to normalize all other pointers. This could be any pointer
// as long as all other pointers are normalized to the same value and the final DispatchEntry
@@ -310,11 +310,19 @@
motionEntry.pointerProperties, pointerCoords, 0 /* xOffset */,
0 /* yOffset */);
- return std::make_unique<DispatchEntry>(combinedMotionEntry, // increments ref
- inputTargetFlags, firstPointerInfo.xOffset,
- firstPointerInfo.yOffset, inputTarget.globalScaleFactor,
- firstPointerInfo.windowXScale,
- firstPointerInfo.windowYScale);
+ if (motionEntry.injectionState) {
+ combinedMotionEntry->injectionState = motionEntry.injectionState;
+ combinedMotionEntry->injectionState->refCount += 1;
+ }
+
+ std::unique_ptr<DispatchEntry> dispatchEntry =
+ std::make_unique<DispatchEntry>(combinedMotionEntry, // increments ref
+ inputTargetFlags, firstPointerInfo.xOffset,
+ firstPointerInfo.yOffset, inputTarget.globalScaleFactor,
+ firstPointerInfo.windowXScale,
+ firstPointerInfo.windowYScale);
+ combinedMotionEntry->release();
+ return dispatchEntry;
}
// --- InputDispatcherThread ---
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index 56c0a73..f8d5351 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -169,6 +169,9 @@
// Used to determine which DisplayViewport should be tied to which InputDevice.
std::unordered_map<std::string, uint8_t> portAssociations;
+ // The suggested display ID to show the cursor.
+ int32_t defaultPointerDisplayId;
+
// Velocity control parameters for mouse pointer movements.
VelocityControlParameters pointerVelocityControlParameters;
@@ -273,6 +276,7 @@
std::optional<DisplayViewport> getDisplayViewportByUniqueId(const std::string& uniqueDisplayId)
const;
std::optional<DisplayViewport> getDisplayViewportByPort(uint8_t physicalPort) const;
+ std::optional<DisplayViewport> getDisplayViewportById(int32_t displayId) const;
void setDisplayViewports(const std::vector<DisplayViewport>& viewports);
@@ -352,4 +356,4 @@
} // namespace android
-#endif // _UI_INPUT_READER_COMMON_H
\ No newline at end of file
+#endif // _UI_INPUT_READER_COMMON_H
diff --git a/services/inputflinger/include/PointerControllerInterface.h b/services/inputflinger/include/PointerControllerInterface.h
index 0ff28e4..194c665 100644
--- a/services/inputflinger/include/PointerControllerInterface.h
+++ b/services/inputflinger/include/PointerControllerInterface.h
@@ -17,6 +17,7 @@
#ifndef _INPUTFLINGER_POINTER_CONTROLLER_INTERFACE_H
#define _INPUTFLINGER_POINTER_CONTROLLER_INTERFACE_H
+#include <input/DisplayViewport.h>
#include <input/Input.h>
#include <utils/BitSet.h>
#include <utils/RefBase.h>
@@ -101,6 +102,9 @@
/* Gets the id of the display where the pointer should be shown. */
virtual int32_t getDisplayId() const = 0;
+
+ /* Sets the associated display of this pointer. Pointer should show on that display. */
+ virtual void setDisplayViewport(const DisplayViewport& displayViewport) = 0;
};
} // namespace android
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index f69138e..69a75ba 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -189,12 +189,32 @@
// Update the PointerController if viewports changed.
if (mParameters.mode == Parameters::MODE_POINTER) {
- getPolicy()->obtainPointerController(getDeviceId());
+ updatePointerControllerDisplayViewport(*config);
}
bumpGeneration();
}
}
+void CursorInputMapper::updatePointerControllerDisplayViewport(
+ const InputReaderConfiguration& config) {
+ std::optional<DisplayViewport> viewport =
+ config.getDisplayViewportById(config.defaultPointerDisplayId);
+ if (!viewport) {
+ ALOGW("Can't find the designated viewport with ID %" PRId32 " to update cursor input "
+ "mapper. Fall back to default display",
+ config.defaultPointerDisplayId);
+ viewport = config.getDisplayViewportById(ADISPLAY_ID_DEFAULT);
+ }
+
+ if (!viewport) {
+ ALOGE("Still can't find a viable viewport to update cursor input mapper. Skip setting it to"
+ " PointerController.");
+ return;
+ }
+
+ mPointerController->setDisplayViewport(*viewport);
+}
+
void CursorInputMapper::configureParameters() {
mParameters.mode = Parameters::MODE_POINTER;
String8 cursorModeString;
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h
index 77d122a..d56f9be 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.h
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.h
@@ -117,8 +117,9 @@
void dumpParameters(std::string& dump);
void sync(nsecs_t when);
+ void updatePointerControllerDisplayViewport(const InputReaderConfiguration& config);
};
} // namespace android
-#endif // _UI_INPUTREADER_CURSOR_INPUT_MAPPER_H
\ No newline at end of file
+#endif // _UI_INPUTREADER_CURSOR_INPUT_MAPPER_H
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
index c567c8b..f42ddcf 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
@@ -209,6 +209,8 @@
return AMOTION_EVENT_TOOL_TYPE_FINGER;
case MT_TOOL_PEN:
return AMOTION_EVENT_TOOL_TYPE_STYLUS;
+ case MT_TOOL_PALM:
+ return AMOTION_EVENT_TOOL_TYPE_PALM;
}
}
return AMOTION_EVENT_TOOL_TYPE_UNKNOWN;
@@ -247,6 +249,14 @@
continue;
}
+ if (inSlot->getToolType() == AMOTION_EVENT_TOOL_TYPE_PALM) {
+ if (!mCurrentMotionAborted) {
+ ALOGI("Canceling touch gesture from device %s because the palm event was detected",
+ getDeviceName().c_str());
+ cancelTouch(when);
+ }
+ }
+
if (outCount >= MAX_POINTERS) {
#if DEBUG_POINTERS
ALOGD("MultiTouch device %s emitted more than maximum of %d pointers; "
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index c80a2dc..b66caca 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -552,9 +552,10 @@
* Determine which DisplayViewport to use.
* 1. If display port is specified, return the matching viewport. If matching viewport not
* found, then return.
- * 2. If a device has associated display, get the matching viewport by either unique id or by
+ * 2. Always use the suggested viewport from WindowManagerService for pointers.
+ * 3. If a device has associated display, get the matching viewport by either unique id or by
* the display type (internal or external).
- * 3. Otherwise, use a non-display viewport.
+ * 4. Otherwise, use a non-display viewport.
*/
std::optional<DisplayViewport> TouchInputMapper::findViewport() {
if (mParameters.hasAssociatedDisplay) {
@@ -564,6 +565,17 @@
return mDevice->getAssociatedViewport();
}
+ if (mDeviceMode == DEVICE_MODE_POINTER) {
+ std::optional<DisplayViewport> viewport =
+ mConfig.getDisplayViewportById(mConfig.defaultPointerDisplayId);
+ if (viewport) {
+ return viewport;
+ } else {
+ ALOGW("Can't find designated display viewport with ID %" PRId32 " for pointers.",
+ mConfig.defaultPointerDisplayId);
+ }
+ }
+
// Check if uniqueDisplayId is specified in idc file.
if (!mParameters.uniqueDisplayId.empty()) {
return mConfig.getDisplayViewportByUniqueId(mParameters.uniqueDisplayId);
@@ -749,6 +761,7 @@
(mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) {
if (mPointerController == nullptr || viewportChanged) {
mPointerController = getPolicy()->obtainPointerController(getDeviceId());
+ mPointerController->setDisplayViewport(mViewport);
}
} else {
mPointerController.clear();
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 1fc8217..8ca7e4a 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -90,10 +90,6 @@
mMaxY = maxY;
}
- void setDisplayId(int32_t displayId) {
- mDisplayId = displayId;
- }
-
virtual void setPosition(float x, float y) {
mX = x;
mY = y;
@@ -116,6 +112,10 @@
return mDisplayId;
}
+ virtual void setDisplayViewport(const DisplayViewport& viewport) {
+ mDisplayId = viewport.displayId;
+ }
+
const std::map<int32_t, std::vector<int32_t>>& getSpots() {
return mSpotsByDisplay;
}
@@ -280,6 +280,10 @@
mConfig.showTouches = enabled;
}
+ void setDefaultPointerDisplayId(int32_t pointerDisplayId) {
+ mConfig.defaultPointerDisplayId = pointerDisplayId;
+ }
+
private:
DisplayViewport createDisplayViewport(int32_t displayId, int32_t width, int32_t height,
int32_t orientation, const std::string& uniqueId, std::optional<uint8_t> physicalPort,
@@ -3432,12 +3436,18 @@
CursorInputMapper* mapper = new CursorInputMapper(mDevice);
addMapperAndConfigure(mapper);
- // Setup PointerController for second display.
+ // Setup for second display.
constexpr int32_t SECOND_DISPLAY_ID = 1;
+ const std::string SECOND_DISPLAY_UNIQUE_ID = "local:1";
+ mFakePolicy->addDisplayViewport(SECOND_DISPLAY_ID, 800, 480, DISPLAY_ORIENTATION_0,
+ SECOND_DISPLAY_UNIQUE_ID, NO_PORT,
+ ViewportType::VIEWPORT_EXTERNAL);
+ mFakePolicy->setDefaultPointerDisplayId(SECOND_DISPLAY_ID);
+ configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+
mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1);
mFakePointerController->setPosition(100, 200);
mFakePointerController->setButtonState(0);
- mFakePointerController->setDisplayId(SECOND_DISPLAY_ID);
NotifyMotionArgs args;
process(mapper, ARBITRARY_TIME, EV_REL, REL_X, 10);
@@ -6539,14 +6549,16 @@
}
TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShouldHandleDisplayId) {
- // Setup PointerController for second display.
+ // Setup for second display.
sp<FakePointerController> fakePointerController = new FakePointerController();
- fakePointerController->setBounds(0, 0, 800 - 1, 480 - 1);
+ fakePointerController->setBounds(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1);
fakePointerController->setPosition(100, 200);
fakePointerController->setButtonState(0);
- fakePointerController->setDisplayId(SECONDARY_DISPLAY_ID);
mFakePolicy->setPointerController(mDevice->getId(), fakePointerController);
+ mFakePolicy->setDefaultPointerDisplayId(SECONDARY_DISPLAY_ID);
+ prepareSecondaryDisplay(ViewportType::VIEWPORT_EXTERNAL);
+
MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION);
@@ -6798,4 +6810,95 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
}
+TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleSingleTouch) {
+ MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareAxes(POSITION | ID | SLOT | TOOL_TYPE);
+ addMapperAndConfigure(mapper);
+
+ NotifyMotionArgs motionArgs;
+
+ constexpr int32_t x1 = 100, y1 = 200, x2 = 120, y2 = 220, x3 = 140, y3 = 240;
+ // finger down
+ processId(mapper, 1);
+ processPosition(mapper, x1, y1);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+ ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+
+ // finger move
+ processId(mapper, 1);
+ processPosition(mapper, x2, y2);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+ ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+
+ // finger up.
+ processId(mapper, -1);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action);
+ ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+
+ // new finger down
+ processId(mapper, 1);
+ processPosition(mapper, x3, y3);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+ ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+}
+
+/**
+ * Test touch should be canceled when received the MT_TOOL_PALM event, and the following MOVE and
+ * UP events should be ignored.
+ */
+TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType) {
+ MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareAxes(POSITION | ID | SLOT | TOOL_TYPE);
+ addMapperAndConfigure(mapper);
+
+ NotifyMotionArgs motionArgs;
+
+ // default tool type is finger
+ constexpr int32_t x1 = 100, y1 = 200, x2 = 120, y2 = 220, x3 = 140, y3 = 240;
+ processId(mapper, 1);
+ processPosition(mapper, x1, y1);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+ ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+
+ // Tool changed to MT_TOOL_PALM expect sending the cancel event.
+ processToolType(mapper, MT_TOOL_PALM);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionArgs.action);
+
+ // Ignore the following MOVE and UP events if had detect a palm event.
+ processId(mapper, 1);
+ processPosition(mapper, x2, y2);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+
+ // finger up.
+ processId(mapper, -1);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+
+ // new finger down
+ processToolType(mapper, MT_TOOL_FINGER);
+ processId(mapper, 1);
+ processPosition(mapper, x3, y3);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+ ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+}
+
} // namespace android
diff --git a/services/sensorservice/SensorServiceUtils.cpp b/services/sensorservice/SensorServiceUtils.cpp
index 34cd8dd..fdd56b3 100644
--- a/services/sensorservice/SensorServiceUtils.cpp
+++ b/services/sensorservice/SensorServiceUtils.cpp
@@ -55,6 +55,7 @@
case SENSOR_TYPE_MOTION_DETECT:
case SENSOR_TYPE_HEART_BEAT:
case SENSOR_TYPE_LOW_LATENCY_OFFBODY_DETECT:
+ case SENSOR_TYPE_HINGE_ANGLE:
return 1;
default:
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 4c5e5da..1b1e889 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -7,6 +7,7 @@
"-Wthread-safety",
"-Wunused",
"-Wunreachable-code",
+ "-Wconversion",
],
}
@@ -78,6 +79,7 @@
"android.hardware.graphics.composer@2.1-command-buffer",
"android.hardware.graphics.composer@2.2-command-buffer",
"android.hardware.graphics.composer@2.3-command-buffer",
+ "android.hardware.graphics.composer@2.4-command-buffer",
],
export_static_lib_headers: [
"libcompositionengine",
@@ -163,7 +165,9 @@
"Scheduler/EventThread.cpp",
"Scheduler/OneShotTimer.cpp",
"Scheduler/LayerHistory.cpp",
+ "Scheduler/LayerHistoryV2.cpp",
"Scheduler/LayerInfo.cpp",
+ "Scheduler/LayerInfoV2.cpp",
"Scheduler/MessageQueue.cpp",
"Scheduler/PhaseOffsets.cpp",
"Scheduler/RefreshRateConfigs.cpp",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 3b1b796..35d0215 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
//#define LOG_NDEBUG 0
#undef LOG_TAG
#define LOG_TAG "BufferLayer"
@@ -140,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;
}
@@ -179,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);
@@ -195,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();
@@ -260,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 {
@@ -795,3 +805,6 @@
#if defined(__gl2_h_)
#error "don't include gl2/gl2.h in this file"
#endif
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
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/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index ea55795..5e04d95 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#undef LOG_TAG
#define LOG_TAG "BufferLayerConsumer"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
@@ -519,3 +523,6 @@
}
}
}; // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index e4e4bc7..e85281d 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#undef LOG_TAG
#define LOG_TAG "BufferQueueLayer"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
@@ -117,6 +121,21 @@
return isDue || !isPlausible;
}
+bool BufferQueueLayer::setFrameRate(float frameRate) {
+ float oldFrameRate = 0.f;
+ status_t result = mConsumer->getFrameRate(&oldFrameRate);
+ bool frameRateChanged = result < 0 || frameRate != oldFrameRate;
+ mConsumer->setFrameRate(frameRate);
+ return frameRateChanged;
+}
+
+std::optional<float> BufferQueueLayer::getFrameRate() const {
+ if (mLatchedFrameRate > 0.f || mLatchedFrameRate == FRAME_RATE_NO_VOTE)
+ return mLatchedFrameRate;
+
+ return {};
+}
+
// -----------------------------------------------------------------------
// Interface implementation for BufferLayer
// -----------------------------------------------------------------------
@@ -547,6 +566,9 @@
mBufferInfo.mApi = mConsumer->getCurrentApi();
mBufferInfo.mPixelFormat = mFormat;
mBufferInfo.mTransformToDisplayInverse = mConsumer->getTransformToDisplayInverse();
+ float latchedFrameRate;
+ mConsumer->getFrameRate(&latchedFrameRate);
+ mLatchedFrameRate = latchedFrameRate;
}
sp<Layer> BufferQueueLayer::createClone() {
@@ -612,3 +634,6 @@
// -----------------------------------------------------------------------
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index b040556..2bd1e3d 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -55,6 +55,10 @@
int32_t getQueuedFrameCount() const override;
bool shouldPresentNow(nsecs_t expectedPresentTime) const override;
+
+ bool setFrameRate(float frameRate) override;
+ std::optional<float> getFrameRate() const override;
+
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
@@ -151,6 +155,8 @@
std::atomic<bool> mSidebandStreamChanged{false};
sp<ContentsChangedListener> mContentsChangedListener;
+
+ std::atomic<float> mLatchedFrameRate = 0.f;
};
} // namespace android
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 067aa46..cd4227c 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
//#define LOG_NDEBUG 0
#undef LOG_TAG
#define LOG_TAG "BufferStateLayer"
@@ -235,6 +239,8 @@
mReleasePreviousBuffer = true;
}
+ mFrameCounter++;
+
mCurrentState.buffer = buffer;
mCurrentState.clientCacheId = clientCacheId;
mCurrentState.modified = true;
@@ -247,7 +253,8 @@
FrameTracer::FrameEvent::POST);
mCurrentState.desiredPresentTime = desiredPresentTime;
- mFlinger->mScheduler->recordLayerHistory(this, desiredPresentTime);
+ mFlinger->mScheduler->recordLayerHistory(this,
+ desiredPresentTime <= 0 ? 0 : desiredPresentTime);
return true;
}
@@ -492,6 +499,8 @@
handle->latchTime = latchTime;
}
+ mFrameNumber = mFrameCounter;
+
if (!SyncFeatures::getInstance().useNativeFenceSync()) {
// Bind the new buffer to the GL texture.
//
@@ -553,8 +562,6 @@
compositionState.buffer = mBufferInfo.mBuffer;
compositionState.bufferSlot = mBufferInfo.mBufferSlot;
compositionState.acquireFence = mBufferInfo.mFence;
-
- mFrameNumber++;
}
void BufferStateLayer::HwcSlotGenerator::bufferErased(const client_cache_t& clientCacheId) {
@@ -681,3 +688,6 @@
return layer;
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
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/Client.cpp b/services/surfaceflinger/Client.cpp
index f331364..fb72ab8 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <stdint.h>
#include <sys/types.h>
@@ -131,3 +135,6 @@
// ---------------------------------------------------------------------------
}; // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index 8bfa569..04854d0 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
// #define LOG_NDEBUG 0
#undef LOG_TAG
#define LOG_TAG "ColorLayer"
@@ -46,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) {
@@ -116,3 +120,6 @@
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
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 18477bb..a634f2f 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -35,6 +35,7 @@
"android.hardware.graphics.composer@2.1-command-buffer",
"android.hardware.graphics.composer@2.2-command-buffer",
"android.hardware.graphics.composer@2.3-command-buffer",
+ "android.hardware.graphics.composer@2.4-command-buffer",
"libsurfaceflinger_headers",
],
}
@@ -43,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/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h
index d93bfa3..67e6deb 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h
@@ -19,8 +19,15 @@
#include <cstdint>
#include <string>
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <ui/GraphicTypes.h>
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
+
namespace android {
class HdrCapabilities;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfileCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfileCreationArgs.h
index ef0f925..7eb8eb1 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfileCreationArgs.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfileCreationArgs.h
@@ -20,7 +20,15 @@
#include <unordered_map>
#include <vector>
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <ui/GraphicTypes.h>
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
+
#include <ui/HdrCapabilities.h>
namespace android::compositionengine {
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index e432b1c..26442d9 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -20,7 +20,15 @@
#include <ostream>
#include <unordered_set>
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <renderengine/LayerSettings.h>
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
+
#include <utils/RefBase.h>
#include <utils/Timers.h>
@@ -89,16 +97,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 +143,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 +165,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/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index a64fdbf..1af99c5 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -18,18 +18,26 @@
#include <cstdint>
-#include <gui/BufferQueue.h>
#include <gui/HdrMetadata.h>
#include <math/mat4.h>
#include <ui/FloatRect.h>
-#include <ui/GraphicBuffer.h>
-#include <ui/GraphicTypes.h>
#include <ui/Rect.h>
#include <ui/Region.h>
#include <ui/Transform.h>
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include <gui/BufferQueue.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicTypes.h>
+
#include "DisplayHardware/ComposerHal.h"
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
+
namespace android::compositionengine {
/*
@@ -63,6 +71,9 @@
// The alpha value for this layer
float alpha{1.f};
+ // Background blur in pixels
+ int backgroundBlurRadius{0};
+
// The transform from layer local coordinates to composition coordinates
ui::Transform geomLayerTransform;
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/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
index a9a95cd..a466561 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
@@ -21,9 +21,16 @@
#include <utils/StrongPointer.h>
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include "DisplayHardware/ComposerHal.h"
#include "DisplayHardware/DisplayIdentification.h"
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
+
namespace HWC2 {
class Layer;
} // namespace HWC2
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/HwcBufferCache.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
index 8eec035..2864c10 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
@@ -19,7 +19,15 @@
#include <cstdint>
#include <vector>
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <gui/BufferQueue.h>
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
+
#include <utils/StrongPointer.h>
namespace android {
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 159e928..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;
@@ -116,6 +118,7 @@
private:
void dirtyEntireOutput();
+ compositionengine::OutputLayer* findLayerRequestingBackgroundComposition() const;
ui::Dataspace getBestDataspace(ui::Dataspace*, bool*) const;
compositionengine::Output::ColorProfile pickColorProfile(
const compositionengine::CompositionRefreshArgs&) const;
@@ -126,6 +129,8 @@
std::unique_ptr<compositionengine::RenderSurface> mRenderSurface;
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..e700b76 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -19,7 +19,16 @@
#include <cstdint>
#include <math/mat4.h>
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <ui/GraphicTypes.h>
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
+
#include <ui/Rect.h>
#include <ui/Region.h>
#include <ui/Transform.h>
@@ -45,6 +54,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/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
index 00baa89..b0a9bc9 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
@@ -27,8 +27,15 @@
#include <ui/Rect.h>
#include <ui/Region.h>
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include "DisplayHardware/ComposerHal.h"
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
+
namespace HWC2 {
class Layer;
} // namespace HWC2
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/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
index 5eabecd..aeaa18a 100644
--- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
@@ -20,11 +20,19 @@
#include <compositionengine/impl/CompositionEngine.h>
#include <compositionengine/impl/Display.h>
#include <compositionengine/impl/Layer.h>
+
#include <renderengine/RenderEngine.h>
#include <utils/Trace.h>
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include "DisplayHardware/HWComposer.h"
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
+
namespace android::compositionengine {
CompositionEngine::~CompositionEngine() = default;
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index e885629..ccd6572 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -25,9 +25,18 @@
#include <compositionengine/impl/DumpHelpers.h>
#include <compositionengine/impl/OutputLayer.h>
#include <compositionengine/impl/RenderSurface.h>
+
#include <utils/Trace.h>
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include "DisplayHardware/HWComposer.h"
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
+
#include "DisplayHardware/PowerAdvisor.h"
namespace android::compositionengine::impl {
@@ -133,6 +142,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 f72862b..cedc333 100644
--- a/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
@@ -15,9 +15,17 @@
*/
#include <compositionengine/impl/HwcBufferCache.h>
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <gui/BufferQueue.h>
#include <ui/GraphicBuffer.h>
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
+
namespace android::compositionengine::impl {
HwcBufferCache::HwcBufferCache() {
@@ -31,7 +39,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/LayerFECompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
index e740529..016084f 100644
--- a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
@@ -57,6 +57,7 @@
out.append("\n ");
dumpVal(out, "blend", toString(blendMode), blendMode);
dumpVal(out, "alpha", alpha);
+ dumpVal(out, "backgroundBlurRadius", backgroundBlurRadius);
out.append("\n ");
dumpVal(out, "type", type);
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 6e28167..55371df 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -28,8 +28,17 @@
#include <compositionengine/impl/OutputCompositionState.h>
#include <compositionengine/impl/OutputLayer.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <renderengine/DisplaySettings.h>
#include <renderengine/RenderEngine.h>
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
+
#include <ui/DebugUtils.h>
#include <ui/HdrCapabilities.h>
#include <utils/Trace.h>
@@ -97,7 +106,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;
@@ -227,6 +236,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);
}
@@ -429,7 +446,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);
@@ -453,7 +470,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.
@@ -574,15 +591,33 @@
return;
}
+ mLayerRequestingBackgroundBlur = findLayerRequestingBackgroundComposition();
+ bool forceClientComposition = mLayerRequestingBackgroundBlur != nullptr;
+
for (auto* layer : getOutputLayersOrderedByZ()) {
layer->updateCompositionState(refreshArgs.updatingGeometryThisFrame,
- refreshArgs.devOptForceClientComposition);
+ refreshArgs.devOptForceClientComposition ||
+ forceClientComposition);
+
+ if (mLayerRequestingBackgroundBlur == layer) {
+ forceClientComposition = false;
+ }
// Send the updated state to the HWC, if appropriate.
layer->writeStateToHWC(refreshArgs.updatingGeometryThisFrame);
}
}
+compositionengine::OutputLayer* Output::findLayerRequestingBackgroundComposition() const {
+ compositionengine::OutputLayer* layerRequestingBgComposition = nullptr;
+ for (auto* layer : getOutputLayersOrderedByZ()) {
+ if (layer->getLayer().getFEState().backgroundBlurRadius > 0) {
+ layerRequestingBgComposition = layer;
+ }
+ }
+ return layerRequestingBgComposition;
+}
+
void Output::updateColorProfile(const compositionengine::CompositionRefreshArgs& refreshArgs) {
setColorProfile(pickColorProfile(refreshArgs));
}
@@ -784,6 +819,7 @@
ALOGV(__FUNCTION__);
const auto& outputState = getState();
+ OutputCompositionState& outputCompositionState = editState();
const TracedOrdinal<bool> hasClientComposition = {"hasClientComposition",
outputState.usesClientComposition};
base::unique_fd readyFence;
@@ -817,7 +853,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);
@@ -849,20 +885,49 @@
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
- // and it's expensive. We boost the GPU frequency so that GPU composition can
- // finish in time. We must reset GPU frequency afterwards, because high frequency
- // consumes extra battery.
+ // 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,
+ // because high frequency consumes extra battery.
const bool expensiveRenderingExpected =
- clientCompositionDisplay.outputDataspace == ui::Dataspace::DISPLAY_P3;
+ clientCompositionDisplay.outputDataspace == ui::Dataspace::DISPLAY_P3 ||
+ mLayerRequestingBackgroundBlur != nullptr;
if (expensiveRenderingExpected) {
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());
@@ -875,9 +940,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();
@@ -921,15 +986,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) {
@@ -956,13 +1023,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);
@@ -1042,6 +1108,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 82d2422..d92b7ef 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -24,8 +24,15 @@
#include <compositionengine/impl/OutputLayer.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include "DisplayHardware/HWComposer.h"
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
+
namespace android::compositionengine {
OutputLayer::~OutputLayer() = default;
@@ -388,7 +395,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));
@@ -645,3 +653,4 @@
} // namespace impl
} // namespace android::compositionengine
+
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
index cc3c54c..165e320 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
@@ -17,8 +17,15 @@
#include <compositionengine/impl/DumpHelpers.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include "DisplayHardware/HWC2.h"
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
+
namespace android::compositionengine::impl {
namespace {
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index 949feb4..660baff 100644
--- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -25,6 +25,7 @@
#include <compositionengine/impl/DumpHelpers.h>
#include <compositionengine/impl/OutputCompositionState.h>
#include <compositionengine/impl/RenderSurface.h>
+
#include <log/log.h>
#include <renderengine/RenderEngine.h>
#include <sync/sync.h>
@@ -33,8 +34,15 @@
#include <ui/Rect.h>
#include <utils/Trace.h>
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include "DisplayHardware/HWComposer.h"
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
+
namespace android::compositionengine {
RenderSurface::~RenderSurface() = default;
@@ -87,7 +95,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 989494d..c1faa90 100644
--- a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
@@ -135,14 +135,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/MockHWC2.h b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
index 7fd6541..a51cc67 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
@@ -20,13 +20,21 @@
#include <ui/Fence.h>
#include <ui/FloatRect.h>
#include <ui/GraphicBuffer.h>
-#include <ui/GraphicTypes.h>
+
#include <ui/Rect.h>
#include <ui/Region.h>
#include <ui/Transform.h>
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include <ui/GraphicTypes.h>
#include "DisplayHardware/HWC2.h"
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
+
namespace HWC2 {
namespace mock {
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 9971791..502a33f 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -19,8 +19,15 @@
#include <compositionengine/Output.h>
#include <gmock/gmock.h>
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include "DisplayHardware/HWComposer.h"
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
+
namespace android {
namespace mock {
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 80528e3..6e8d3df 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -43,12 +43,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;
@@ -58,10 +60,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);
@@ -134,6 +137,10 @@
EXPECT_CALL(mLayer1, editFEState()).WillRepeatedly(ReturnRef(mLayer1FEState));
EXPECT_CALL(mLayer2, editFEState()).WillRepeatedly(ReturnRef(mLayer2FEState));
EXPECT_CALL(mLayer3, editFEState()).WillRepeatedly(ReturnRef(mLayer3FEState));
+
+ EXPECT_CALL(mLayer1, getFEState()).WillRepeatedly(ReturnRef(mLayer1FEState));
+ EXPECT_CALL(mLayer2, getFEState()).WillRepeatedly(ReturnRef(mLayer2FEState));
+ EXPECT_CALL(mLayer3, getFEState()).WillRepeatedly(ReturnRef(mLayer3FEState));
}
void injectLayer(std::unique_ptr<mock::OutputLayer> layer) {
@@ -980,7 +987,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))
@@ -1004,7 +1011,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());
@@ -1054,7 +1061,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));
@@ -1619,7 +1626,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,
@@ -1634,7 +1641,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;
}
@@ -1682,7 +1689,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),
@@ -1738,7 +1745,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());
}
@@ -1860,7 +1867,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());
}
@@ -1913,7 +1920,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());
}
@@ -2193,7 +2200,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));
@@ -2757,9 +2764,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));
};
@@ -2767,6 +2774,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;
@@ -2779,6 +2787,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));
@@ -2834,7 +2843,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{{},
@@ -2855,7 +2864,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());
@@ -2869,7 +2878,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());
@@ -2881,8 +2890,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};
@@ -2891,26 +2900,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));
@@ -3040,7 +3166,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));
@@ -3158,7 +3284,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;
@@ -3176,7 +3302,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,
@@ -3198,7 +3324,7 @@
StrictMock<mock::LayerFE> mLayerFE;
LayerFECompositionState mLayerFEState;
impl::OutputLayerCompositionState mOutputLayerState;
- renderengine::LayerSettings mRELayerSettings;
+ LayerFE::LayerSettings mLayerSettings;
};
GenerateClientCompositionRequestsTest() {
@@ -3229,11 +3355,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));
@@ -3284,30 +3410,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))));
@@ -3332,7 +3458,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));
@@ -3340,7 +3466,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))));
}
@@ -3360,7 +3486,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));
@@ -3368,7 +3494,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))));
}
@@ -3393,9 +3519,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));
@@ -3405,13 +3531,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))));
}
@@ -3633,6 +3759,29 @@
kDisplayDataspace));
}
+TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBackgroundBlurRequests) {
+ // Layer requesting blur, or below, should request client composition.
+ EXPECT_CALL(*mOutputLayer1, updateCompositionState(false, true));
+ EXPECT_CALL(*mOutputLayer1, writeStateToHWC(false));
+ EXPECT_CALL(*mOutputLayer2, updateCompositionState(false, true));
+ EXPECT_CALL(*mOutputLayer2, writeStateToHWC(false));
+ EXPECT_CALL(*mOutputLayer3, updateCompositionState(false, false));
+ EXPECT_CALL(*mOutputLayer3, writeStateToHWC(false));
+
+ mLayer2FEState.backgroundBlurRadius = 10;
+
+ injectLayer(std::move(mOutputLayer1));
+ injectLayer(std::move(mOutputLayer2));
+ injectLayer(std::move(mOutputLayer3));
+
+ mOutput->editState().isEnabled = true;
+
+ CompositionRefreshArgs args;
+ args.updatingGeometryThisFrame = false;
+ args.devOptForceClientComposition = false;
+ mOutput->updateAndWriteCompositionState(args);
+}
+
TEST_F(GenerateClientCompositionRequestsTest, handlesLandscapeModeSplitScreenRequests) {
// In split-screen landscape mode, the screen is rotated 90 degrees, with
// one layer on the left covering the left side of the output, and one layer
@@ -3658,12 +3807,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))
@@ -3685,9 +3834,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));
@@ -3703,9 +3852,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));
@@ -3713,8 +3862,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,
@@ -3724,8 +3873,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;
@@ -3733,18 +3882,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,
@@ -3755,8 +3904,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;
@@ -3764,19 +3913,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/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index ab664be..841e79f 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
// #define LOG_NDEBUG 0
#undef LOG_TAG
#define LOG_TAG "ContainerLayer"
@@ -39,3 +43,6 @@
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index e0dc3e7..4ae6dad 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
// #define LOG_NDEBUG 0
#undef LOG_TAG
#define LOG_TAG "DisplayDevice"
@@ -66,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),
@@ -327,3 +337,6 @@
std::atomic<int32_t> DisplayDeviceState::sNextSequenceId(1);
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 605e7c8..ff48ecd 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -227,8 +227,10 @@
public:
DisplayRenderArea(const sp<const DisplayDevice>& display,
RotationFlags rotation = ui::Transform::ROT_0)
- : DisplayRenderArea(display, display->getBounds(), display->getWidth(),
- display->getHeight(), display->getCompositionDataSpace(), rotation) {}
+ : DisplayRenderArea(display, display->getBounds(),
+ static_cast<uint32_t>(display->getWidth()),
+ static_cast<uint32_t>(display->getHeight()),
+ display->getCompositionDataSpace(), rotation) {}
DisplayRenderArea(sp<const DisplayDevice> display, const Rect& sourceCrop, uint32_t reqWidth,
uint32_t reqHeight, ui::Dataspace reqDataSpace, RotationFlags rotation,
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index eb032f3..97eeea2 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#undef LOG_TAG
#define LOG_TAG "HwcComposer"
@@ -1320,6 +1324,36 @@
return mClient_2_4->setContentType(display, contentType);
}
+V2_4::Error Composer::setLayerGenericMetadata(Display display, Layer layer, const std::string& key,
+ bool mandatory, const std::vector<uint8_t>& value) {
+ using Error = V2_4::Error;
+ if (!mClient_2_4) {
+ return Error::UNSUPPORTED;
+ }
+ mWriter.selectDisplay(display);
+ mWriter.selectLayer(layer);
+ mWriter.setLayerGenericMetadata(key, mandatory, value);
+ return Error::NONE;
+}
+
+V2_4::Error Composer::getLayerGenericMetadataKeys(
+ std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) {
+ using Error = V2_4::Error;
+ if (!mClient_2_4) {
+ return Error::UNSUPPORTED;
+ }
+ Error error = kDefaultError_2_4;
+ mClient_2_4->getLayerGenericMetadataKeys([&](const auto& tmpError, const auto& tmpKeys) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ *outKeys = tmpKeys;
+ });
+ return error;
+}
+
CommandReader::~CommandReader()
{
resetData();
@@ -1333,8 +1367,7 @@
uint16_t length = 0;
while (!isEmpty()) {
- auto command_2_1 = reinterpret_cast<V2_1::IComposerClient::Command*>(&command);
- if (!beginCommand(command_2_1, &length)) {
+ if (!beginCommand(&command, &length)) {
break;
}
@@ -1361,6 +1394,9 @@
case IComposerClient::Command ::SET_PRESENT_OR_VALIDATE_DISPLAY_RESULT:
parsed = parseSetPresentOrValidateDisplayResult(length);
break;
+ case IComposerClient::Command::SET_CLIENT_TARGET_PROPERTY:
+ parsed = parseSetClientTargetProperty(length);
+ break;
default:
parsed = false;
break;
@@ -1498,6 +1534,15 @@
return true;
}
+bool CommandReader::parseSetClientTargetProperty(uint16_t length) {
+ if (length != CommandWriterBase::kSetClientTargetPropertyLength || !mCurrentReturnData) {
+ return false;
+ }
+ mCurrentReturnData->clientTargetProperty.pixelFormat = static_cast<PixelFormat>(readSigned());
+ mCurrentReturnData->clientTargetProperty.dataspace = static_cast<Dataspace>(readSigned());
+ return true;
+}
+
void CommandReader::resetData()
{
mErrors.clear();
@@ -1622,3 +1667,6 @@
} // namespace Hwc2
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 301f54f..aa43f09 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -23,19 +23,26 @@
#include <utility>
#include <vector>
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
#include <android/frameworks/vr/composer/2.0/IVrComposerClient.h>
#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
#include <android/hardware/graphics/common/1.1/types.h>
#include <android/hardware/graphics/composer/2.4/IComposer.h>
#include <android/hardware/graphics/composer/2.4/IComposerClient.h>
-#include <composer-command-buffer/2.3/ComposerCommandBuffer.h>
+#include <composer-command-buffer/2.4/ComposerCommandBuffer.h>
#include <gui/HdrMetadata.h>
#include <math/mat4.h>
#include <ui/DisplayedFrameStats.h>
#include <ui/GraphicBuffer.h>
#include <utils/StrongPointer.h>
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
+
namespace android {
namespace Hwc2 {
@@ -63,8 +70,8 @@
using V2_1::Display;
using V2_1::Error;
using V2_1::Layer;
-using V2_3::CommandReaderBase;
-using V2_3::CommandWriterBase;
+using V2_4::CommandReaderBase;
+using V2_4::CommandWriterBase;
using V2_4::IComposer;
using V2_4::IComposerCallback;
using V2_4::IComposerClient;
@@ -228,6 +235,11 @@
std::vector<IComposerClient::ContentType>* outSupportedContentTypes) = 0;
virtual V2_4::Error setContentType(Display displayId,
IComposerClient::ContentType contentType) = 0;
+ virtual V2_4::Error setLayerGenericMetadata(Display display, Layer layer,
+ const std::string& key, bool mandatory,
+ const std::vector<uint8_t>& value) = 0;
+ virtual V2_4::Error getLayerGenericMetadataKeys(
+ std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) = 0;
};
namespace impl {
@@ -280,6 +292,7 @@
bool parseSetPresentFence(uint16_t length);
bool parseSetReleaseFences(uint16_t length);
bool parseSetPresentOrValidateDisplayResult(uint16_t length);
+ bool parseSetClientTargetProperty(uint16_t length);
struct ReturnData {
uint32_t displayRequests = 0;
@@ -296,6 +309,13 @@
std::vector<int> releaseFences;
uint32_t presentOrValidateState;
+
+ // Composer 2.4 implementation can return a client target property
+ // structure to indicate the client target properties that hardware
+ // composer requests. The composer client must change the client target
+ // properties to match this request.
+ IComposerClient::ClientTargetProperty clientTargetProperty{PixelFormat::RGBA_8888,
+ Dataspace::UNKNOWN};
};
std::vector<CommandError> mErrors;
@@ -455,6 +475,10 @@
std::vector<IComposerClient::ContentType>* outSupportedContentTypes) override;
V2_4::Error setContentType(Display displayId,
IComposerClient::ContentType contentType) override;
+ V2_4::Error setLayerGenericMetadata(Display display, Layer layer, const std::string& key,
+ bool mandatory, const std::vector<uint8_t>& value) override;
+ V2_4::Error getLayerGenericMetadataKeys(
+ std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) override;
private:
#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
index ba7818d..277081f 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#undef LOG_TAG
#define LOG_TAG "DisplayIdentification"
@@ -204,3 +208,6 @@
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 7370b0c..36544b6 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -15,6 +15,10 @@
** limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
// #define LOG_NDEBUG 0
#undef LOG_TAG
#define LOG_TAG "FramebufferSurface"
@@ -193,3 +197,6 @@
// ----------------------------------------------------------------------------
}; // namespace android
// ----------------------------------------------------------------------------
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 12b0ddd..41e7879 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
// #define LOG_NDEBUG 0
#undef LOG_TAG
@@ -977,3 +981,6 @@
} // namespace impl
} // namespace HWC2
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 1960f43..153cfe7 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
// #define LOG_NDEBUG 0
#undef LOG_TAG
@@ -948,3 +952,6 @@
} // namespace impl
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index a0dabb4..effe43b 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -27,7 +27,13 @@
#include <android-base/thread_annotations.h>
#include <ui/Fence.h>
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
#include <ui/GraphicTypes.h>
+#pragma clang diagnostic pop
+
#include <utils/StrongPointer.h>
#include <utils/Timers.h>
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 56b0ea6..fba3261 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
// #define LOG_NDEBUG 0
#include "VirtualDisplaySurface.h"
@@ -694,3 +698,6 @@
// ---------------------------------------------------------------------------
} // namespace android
// ---------------------------------------------------------------------------
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Effects/Daltonizer.cpp b/services/surfaceflinger/Effects/Daltonizer.cpp
index 01c9c0f..a7090c5 100644
--- a/services/surfaceflinger/Effects/Daltonizer.cpp
+++ b/services/surfaceflinger/Effects/Daltonizer.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include "Daltonizer.h"
#include <math/mat4.h>
@@ -171,3 +175,6 @@
}
} /* namespace android */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/EventLog/EventLog.cpp b/services/surfaceflinger/EventLog/EventLog.cpp
index a532fc1..3b60952 100644
--- a/services/surfaceflinger/EventLog/EventLog.cpp
+++ b/services/surfaceflinger/EventLog/EventLog.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <stdio.h>
#include <stdlib.h>
#include <log/log.h>
@@ -124,3 +128,6 @@
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/FrameTracer/FrameTracer.cpp b/services/surfaceflinger/FrameTracer/FrameTracer.cpp
index 4418116..b986f38 100644
--- a/services/surfaceflinger/FrameTracer/FrameTracer.cpp
+++ b/services/surfaceflinger/FrameTracer/FrameTracer.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#undef LOG_TAG
#define LOG_TAG "FrameTracer"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
@@ -179,3 +183,6 @@
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/FrameTracker.cpp b/services/surfaceflinger/FrameTracker.cpp
index a6e511e..8ad805b 100644
--- a/services/surfaceflinger/FrameTracker.cpp
+++ b/services/surfaceflinger/FrameTracker.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
// This is needed for stdint.h to define INT64_MAX in C++
#define __STDC_LIMIT_MACROS
@@ -246,3 +250,6 @@
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 2593681..6f8df95 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
//#define LOG_NDEBUG 0
#undef LOG_TAG
#define LOG_TAG "Layer"
@@ -105,11 +109,14 @@
mCurrentState.hdrMetadata.validTypes = 0;
mCurrentState.surfaceDamageRegion = Region::INVALID_REGION;
mCurrentState.cornerRadius = 0.0f;
+ mCurrentState.backgroundBlurRadius = 0;
mCurrentState.api = -1;
mCurrentState.hasColorTransform = false;
mCurrentState.colorSpaceAgnostic = false;
+ mCurrentState.frameRateSelectionPriority = PRIORITY_UNSET;
mCurrentState.metadata = args.metadata;
mCurrentState.shadowRadius = 0.f;
+ mCurrentState.frameRate = 0.f;
// drawing state & current state are identical
mDrawingState = mCurrentState;
@@ -137,7 +144,7 @@
mFlinger->onLayerDestroyed(this);
}
-LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, const sp<Client>& client,
+LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, const sp<Client> client,
std::string name, uint32_t w, uint32_t h, uint32_t flags,
LayerMetadata metadata)
: flinger(flinger),
@@ -442,6 +449,7 @@
compositionState.blendMode = static_cast<Hwc2::IComposerClient::BlendMode>(blendMode);
compositionState.alpha = alpha;
+ compositionState.backgroundBlurRadius = drawingState.backgroundBlurRadius;
}
void Layer::latchGeometry(compositionengine::LayerFECompositionState& compositionState) const {
@@ -543,7 +551,7 @@
// drawing...
// ---------------------------------------------------------------------------
-std::optional<renderengine::LayerSettings> Layer::prepareClientComposition(
+std::optional<compositionengine::LayerFE::LayerSettings> Layer::prepareClientComposition(
compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
if (!getCompositionLayer()) {
return {};
@@ -551,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();
@@ -569,11 +578,12 @@
layerSettings.alpha = alpha;
layerSettings.sourceDataspace = getDataSpace();
+ layerSettings.backgroundBlurRadius = getBackgroundBlurRadius();
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) {
@@ -584,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
@@ -595,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
@@ -1097,6 +1111,16 @@
return true;
}
+bool Layer::setBackgroundBlurRadius(int backgroundBlurRadius) {
+ if (mCurrentState.backgroundBlurRadius == backgroundBlurRadius) return false;
+
+ mCurrentState.sequence++;
+ mCurrentState.backgroundBlurRadius = backgroundBlurRadius;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix,
bool allowNonRectPreservingTransforms) {
ui::Transform t;
@@ -1120,6 +1144,7 @@
setTransactionFlags(eTransactionNeeded);
return true;
}
+
bool Layer::setFlags(uint8_t flags, uint8_t mask) {
const uint32_t newFlags = (mCurrentState.flags & ~mask) | (flags & mask);
if (mCurrentState.flags == newFlags) return false;
@@ -1176,6 +1201,29 @@
return true;
}
+bool Layer::setFrameRateSelectionPriority(int32_t priority) {
+ if (mCurrentState.frameRateSelectionPriority == priority) return false;
+ mCurrentState.frameRateSelectionPriority = priority;
+ mCurrentState.sequence++;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
+int32_t Layer::getFrameRateSelectionPriority() const {
+ // Check if layer has priority set.
+ if (mDrawingState.frameRateSelectionPriority != PRIORITY_UNSET) {
+ return mDrawingState.frameRateSelectionPriority;
+ }
+ // If not, search whether its parents have it set.
+ sp<Layer> parent = getParent();
+ if (parent != nullptr) {
+ return parent->getFrameRateSelectionPriority();
+ }
+
+ return Layer::PRIORITY_UNSET;
+}
+
uint32_t Layer::getLayerStack() const {
auto p = mDrawingParent.promote();
if (p == nullptr) {
@@ -1196,6 +1244,25 @@
return true;
}
+bool Layer::setFrameRate(float frameRate) {
+ if (mCurrentState.frameRate == frameRate) {
+ return false;
+ }
+
+ mCurrentState.sequence++;
+ mCurrentState.frameRate = frameRate;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
+std::optional<float> Layer::getFrameRate() const {
+ const auto frameRate = getDrawingState().frameRate;
+ if (frameRate > 0.f || frameRate == FRAME_RATE_NO_VOTE) return frameRate;
+
+ return {};
+}
+
void Layer::deferTransactionUntil_legacy(const sp<Layer>& barrierLayer, uint64_t frameNumber) {
ATRACE_CALL();
mCurrentState.barrierLayer_legacy = barrierLayer;
@@ -1827,6 +1894,10 @@
return half4(color.r, color.g, color.b, getAlpha());
}
+int32_t Layer::getBackgroundBlurRadius() const {
+ return getDrawingState().backgroundBlurRadius;
+}
+
Layer::RoundedCornerState Layer::getRoundedCornerState() const {
const auto& p = mDrawingParent.promote();
if (p != nullptr) {
@@ -2304,3 +2375,6 @@
#if defined(__gl2_h_)
#error "don't include gl2/gl2.h in this file"
#endif
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 174ac8d..c75a570 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -78,11 +78,11 @@
// ---------------------------------------------------------------------------
struct LayerCreationArgs {
- LayerCreationArgs(SurfaceFlinger* flinger, const sp<Client>& client, std::string name,
+ LayerCreationArgs(SurfaceFlinger* flinger, const sp<Client> client, std::string name,
uint32_t w, uint32_t h, uint32_t flags, LayerMetadata metadata);
SurfaceFlinger* flinger;
- const sp<Client>& client;
+ const sp<Client> client;
std::string name;
uint32_t w;
uint32_t h;
@@ -96,6 +96,7 @@
class Layer : public compositionengine::LayerFE {
static std::atomic<int32_t> sSequence;
+ static constexpr int32_t PRIORITY_UNSET = -1;
public:
mutable bool contentDirty{false};
@@ -178,6 +179,7 @@
half4 color;
float cornerRadius;
+ int backgroundBlurRadius;
bool inputInfoChanged;
InputWindowInfo inputInfo;
@@ -220,6 +222,11 @@
// Length of the cast shadow. If the radius is > 0, a shadow of length shadowRadius will
// be rendered around the layer.
float shadowRadius;
+
+ // Priority of the layer assigned by Window Manager.
+ int32_t frameRateSelectionPriority;
+
+ float frameRate;
};
explicit Layer(const LayerCreationArgs& args);
@@ -293,6 +300,9 @@
// The shape of the rounded corner rectangle is specified by the crop rectangle of the layer
// from which we inferred the rounded corner radius.
virtual bool setCornerRadius(float cornerRadius);
+ // When non-zero, everything below this layer will be blurred by backgroundBlurRadius, which
+ // is specified in pixels.
+ virtual bool setBackgroundBlurRadius(int backgroundBlurRadius);
virtual bool setTransparentRegionHint(const Region& transparent);
virtual bool setFlags(uint8_t flags, uint8_t mask);
virtual bool setLayerStack(uint32_t layerStack);
@@ -337,6 +347,10 @@
virtual bool setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace);
virtual bool setColorSpaceAgnostic(const bool agnostic);
bool setShadowRadius(float shadowRadius);
+ virtual bool setFrameRateSelectionPriority(int32_t priority);
+ // If the variable is not set on the layer, it traverses up the tree to inherit the frame
+ // rate priority from its parent.
+ virtual int32_t getFrameRateSelectionPriority() const;
virtual ui::Dataspace getDataSpace() const { return ui::Dataspace::UNKNOWN; }
@@ -513,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;
@@ -653,6 +667,7 @@
// down the hierarchy).
half getAlpha() const;
half4 getColor() const;
+ int32_t getBackgroundBlurRadius() const;
// Returns how rounded corners should be drawn for this layer.
// This will traverse the hierarchy until it reaches its root, finding topmost rounded
@@ -729,6 +744,10 @@
*/
Rect getCroppedBufferSize(const Layer::State& s) const;
+ constexpr static auto FRAME_RATE_NO_VOTE = -1.0f;
+ virtual bool setFrameRate(float frameRate);
+ virtual std::optional<float> getFrameRate() const;
+
protected:
// constant
sp<SurfaceFlinger> mFlinger;
@@ -755,6 +774,7 @@
// For unit tests
friend class TestableSurfaceFlinger;
+ friend class RefreshRateSelectionTest;
virtual void commitTransaction(const State& stateToCommit);
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index b402270..0fe1421 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include "LayerProtoHelper.h"
namespace android {
@@ -165,3 +169,6 @@
} // namespace surfaceflinger
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp
index 412f977..d3364a0 100644
--- a/services/surfaceflinger/LayerRejecter.cpp
+++ b/services/surfaceflinger/LayerRejecter.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include "LayerRejecter.h"
#include <gui/BufferItem.h>
@@ -136,3 +140,6 @@
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/LayerVector.cpp b/services/surfaceflinger/LayerVector.cpp
index 8271fd9..7c959b9 100644
--- a/services/surfaceflinger/LayerVector.cpp
+++ b/services/surfaceflinger/LayerVector.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include "LayerVector.h"
#include "Layer.h"
@@ -83,3 +87,6 @@
}
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index 7a959f7..40a63d7 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include "MonitoredProducer.h"
#include "Layer.h"
#include "SurfaceFlinger.h"
@@ -158,6 +162,10 @@
return mProducer->setAutoPrerotation(autoPrerotation);
}
+status_t MonitoredProducer::setFrameRate(float frameRate) {
+ return mProducer->setFrameRate(frameRate);
+}
+
IBinder* MonitoredProducer::onAsBinder() {
return this;
}
@@ -168,3 +176,6 @@
// ---------------------------------------------------------------------------
}; // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h
index 788919b..4bda831 100644
--- a/services/surfaceflinger/MonitoredProducer.h
+++ b/services/surfaceflinger/MonitoredProducer.h
@@ -71,6 +71,7 @@
virtual status_t getUniqueId(uint64_t* outId) const override;
virtual status_t getConsumerUsage(uint64_t* outUsage) const override;
virtual status_t setAutoPrerotation(bool autoPrerotation) override;
+ virtual status_t setFrameRate(float frameRate) override;
// The Layer which created this producer, and on which queued Buffer's will be displayed.
sp<Layer> getLayer() const;
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index c69859e..d3d9d3a 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include "RefreshRateOverlay.h"
#include "Client.h"
#include "Layer.h"
@@ -151,6 +155,7 @@
Mutex::Autolock _l(mFlinger.mStateLock);
mLayer = mClient->getLayerUser(mIBinder);
+ mLayer->setFrameRate(Layer::FRAME_RATE_NO_VOTE);
// setting Layer's Z requires resorting layersSortedByZ
ssize_t idx = mFlinger.mCurrentState.layersSortedByZ.indexOf(mLayer);
@@ -211,3 +216,6 @@
}
}; // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 73de4f8..0031d70 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
//#define LOG_NDEBUG 0
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#undef LOG_TAG
@@ -472,3 +476,6 @@
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/RenderArea.cpp b/services/surfaceflinger/RenderArea.cpp
index 93759e8..9a6c853 100644
--- a/services/surfaceflinger/RenderArea.cpp
+++ b/services/surfaceflinger/RenderArea.cpp
@@ -1,3 +1,23 @@
+/*
+ * Copyright 2017 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include "RenderArea.h"
namespace android {
@@ -13,3 +33,6 @@
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
index a7a6dd5..9b3a9f4 100644
--- a/services/surfaceflinger/RenderArea.h
+++ b/services/surfaceflinger/RenderArea.h
@@ -71,8 +71,8 @@
RotationFlags getRotationFlags() const { return mRotationFlags; }
// Returns the size of the physical render area.
- int getReqWidth() const { return mReqWidth; }
- int getReqHeight() const { return mReqHeight; }
+ int getReqWidth() const { return static_cast<int>(mReqWidth); }
+ int getReqHeight() const { return static_cast<int>(mReqHeight); }
// Returns the composition data space of the render area.
ui::Dataspace getReqDataSpace() const { return mReqDataSpace; }
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index 4bdfad9..ca41608 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
//#define LOG_NDEBUG 0
@@ -847,3 +851,6 @@
} // namespace impl
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
index bd4b0ec..776e984 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include "DispSyncSource.h"
@@ -104,3 +108,6 @@
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Scheduler/EventControlThread.cpp b/services/surfaceflinger/Scheduler/EventControlThread.cpp
index 85a7f82..7f9db9c 100644
--- a/services/surfaceflinger/Scheduler/EventControlThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventControlThread.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <pthread.h>
#include <sched.h>
#include <sys/resource.h>
@@ -73,3 +77,6 @@
} // namespace impl
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 5bdef58..14e3ec6 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include <pthread.h>
@@ -517,3 +521,6 @@
} // namespace impl
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index cf79d9f..b976523 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -39,6 +39,9 @@
namespace {
bool isLayerActive(const Layer& layer, const LayerInfo& info, nsecs_t threshold) {
+ if (layer.getFrameRate().has_value()) {
+ return layer.isVisible();
+ }
return layer.isVisible() && info.getLastUpdatedTime() >= threshold;
}
@@ -48,6 +51,12 @@
return atoi(value);
}
+bool useFrameRatePriority() {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.sf.use_frame_rate_priority", value, "1");
+ return atoi(value);
+}
+
void trace(const wp<Layer>& weak, int fps) {
const auto layer = weak.promote();
if (!layer) return;
@@ -60,10 +69,12 @@
} // namespace
-LayerHistory::LayerHistory() : mTraceEnabled(traceEnabled()) {}
+LayerHistory::LayerHistory()
+ : mTraceEnabled(traceEnabled()), mUseFrameRatePriority(useFrameRatePriority()) {}
LayerHistory::~LayerHistory() = default;
-void LayerHistory::registerLayer(Layer* layer, float lowRefreshRate, float highRefreshRate) {
+void LayerHistory::registerLayer(Layer* layer, float lowRefreshRate, float highRefreshRate,
+ LayerVoteType /*type*/) {
auto info = std::make_unique<LayerInfo>(lowRefreshRate, highRefreshRate);
std::lock_guard lock(mLock);
mLayerInfos.emplace_back(layer, std::move(info));
@@ -87,31 +98,51 @@
}
LayerHistory::Summary LayerHistory::summarize(nsecs_t now) {
- float maxRefreshRate = 0;
-
std::lock_guard lock(mLock);
partitionLayers(now);
// Find the maximum refresh rate among recently active layers.
- for (const auto& [layer, info] : activeLayers()) {
+ for (const auto& [activeLayer, info] : activeLayers()) {
const bool recent = info->isRecentlyActive(now);
+
if (recent || CC_UNLIKELY(mTraceEnabled)) {
const float refreshRate = info->getRefreshRate(now);
- if (recent && refreshRate > maxRefreshRate) {
- maxRefreshRate = refreshRate;
- }
-
- if (CC_UNLIKELY(mTraceEnabled)) {
- trace(layer, std::round(refreshRate));
+ if (recent && refreshRate > 0.0f) {
+ if (const auto layer = activeLayer.promote(); layer) {
+ const int32_t priority = layer->getFrameRateSelectionPriority();
+ // TODO(b/142507166): This is where the scoring algorithm should live.
+ // Layers should be organized by priority
+ ALOGD("Layer has priority: %d", priority);
+ }
}
}
}
- if (CC_UNLIKELY(mTraceEnabled)) {
- ALOGD("%s: maxRefreshRate=%.2f", __FUNCTION__, maxRefreshRate);
+
+ LayerHistory::Summary summary;
+ for (const auto& [weakLayer, info] : activeLayers()) {
+ const bool recent = info->isRecentlyActive(now);
+ auto layer = weakLayer.promote();
+ // Only use the layer if the reference still exists.
+ if (layer || CC_UNLIKELY(mTraceEnabled)) {
+ // Check if frame rate was set on layer.
+ auto frameRate = layer->getFrameRate();
+ if (frameRate.has_value() && frameRate.value() > 0.f) {
+ summary.push_back(
+ {layer->getName(), LayerVoteType::Explicit, *frameRate, /* weight */ 1.0f});
+ } else if (recent) {
+ frameRate = info->getRefreshRate(now);
+ summary.push_back({layer->getName(), LayerVoteType::Heuristic, *frameRate,
+ /* weight */ 1.0f});
+ }
+
+ if (CC_UNLIKELY(mTraceEnabled)) {
+ trace(weakLayer, round<int>(*frameRate));
+ }
+ }
}
- return {maxRefreshRate};
+ return summary;
}
void LayerHistory::partitionLayers(nsecs_t now) {
@@ -144,7 +175,7 @@
}
}
- mLayerInfos.erase(mLayerInfos.begin() + end, mLayerInfos.end());
+ mLayerInfos.erase(mLayerInfos.begin() + static_cast<long>(end), mLayerInfos.end());
}
void LayerHistory::clear() {
@@ -158,3 +189,4 @@
}
} // namespace android::scheduler::impl
+
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index d92e5c3..a1ae35c 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -25,6 +25,8 @@
#include <utility>
#include <vector>
+#include "RefreshRateConfigs.h"
+
namespace android {
class Layer;
@@ -33,21 +35,27 @@
namespace scheduler {
class LayerHistoryTest;
+class LayerHistoryTestV2;
class LayerInfo;
+class LayerInfoV2;
class LayerHistory {
public:
+ using LayerVoteType = RefreshRateConfigs::LayerVoteType;
+
virtual ~LayerHistory() = default;
// Layers are unregistered when the weak reference expires.
- virtual void registerLayer(Layer*, float lowRefreshRate, float highRefreshRate) = 0;
+ virtual void registerLayer(Layer*, float lowRefreshRate, float highRefreshRate,
+ LayerVoteType type) = 0;
+
+ // Sets the display size. Client is responsible for synchronization.
+ virtual void setDisplayArea(uint32_t displayArea) = 0;
// Marks the layer as active, and records the given state to its history.
virtual void record(Layer*, nsecs_t presentTime, nsecs_t now) = 0;
- struct Summary {
- float maxRefreshRate; // Maximum refresh rate among recently active layers.
- };
+ using Summary = std::vector<RefreshRateConfigs::LayerRequirement>;
// Rebuilds sets of active/inactive layers, and accumulates stats for active layers.
virtual Summary summarize(nsecs_t now) = 0;
@@ -65,7 +73,10 @@
virtual ~LayerHistory();
// Layers are unregistered when the weak reference expires.
- void registerLayer(Layer*, float lowRefreshRate, float highRefreshRate) override;
+ void registerLayer(Layer*, float lowRefreshRate, float highRefreshRate,
+ LayerVoteType type) override;
+
+ void setDisplayArea(uint32_t /*displayArea*/) override {}
// Marks the layer as active, and records the given state to its history.
void record(Layer*, nsecs_t presentTime, nsecs_t now) override;
@@ -87,7 +98,7 @@
const size_t index;
auto begin() { return infos.begin(); }
- auto end() { return begin() + index; }
+ auto end() { return begin() + static_cast<long>(index); }
};
ActiveLayers activeLayers() REQUIRES(mLock) { return {mLayerInfos, mActiveLayersEnd}; }
@@ -106,6 +117,67 @@
// Whether to emit systrace output and debug logs.
const bool mTraceEnabled;
+
+ // Whether to use priority sent from WindowManager to determine the relevancy of the layer.
+ const bool mUseFrameRatePriority;
+};
+
+class LayerHistoryV2 : public android::scheduler::LayerHistory {
+public:
+ LayerHistoryV2();
+ virtual ~LayerHistoryV2();
+
+ // Layers are unregistered when the weak reference expires.
+ void registerLayer(Layer*, float lowRefreshRate, float highRefreshRate,
+ LayerVoteType type) override;
+
+ // Sets the display size. Client is responsible for synchronization.
+ void setDisplayArea(uint32_t displayArea) override { mDisplayArea = displayArea; }
+
+ // Marks the layer as active, and records the given state to its history.
+ void record(Layer*, nsecs_t presentTime, nsecs_t now) override;
+
+ // Rebuilds sets of active/inactive layers, and accumulates stats for active layers.
+ android::scheduler::LayerHistory::Summary summarize(nsecs_t /*now*/) override;
+
+ void clear() override;
+
+private:
+ friend android::scheduler::LayerHistoryTestV2;
+ friend TestableScheduler;
+
+ using LayerPair = std::pair<wp<Layer>, std::unique_ptr<LayerInfoV2>>;
+ using LayerInfos = std::vector<LayerPair>;
+
+ struct ActiveLayers {
+ LayerInfos& infos;
+ const size_t index;
+
+ auto begin() { return infos.begin(); }
+ auto end() { return begin() + static_cast<long>(index); }
+ };
+
+ ActiveLayers activeLayers() REQUIRES(mLock) { return {mLayerInfos, mActiveLayersEnd}; }
+
+ // Iterates over layers in a single pass, swapping pairs such that active layers precede
+ // inactive layers, and inactive layers precede expired layers. Removes expired layers by
+ // truncating after inactive layers.
+ void partitionLayers(nsecs_t now) REQUIRES(mLock);
+
+ mutable std::mutex mLock;
+
+ // Partitioned such that active layers precede inactive layers. For fast lookup, the few active
+ // layers are at the front, and weak pointers are stored in contiguous memory to hit the cache.
+ LayerInfos mLayerInfos GUARDED_BY(mLock);
+ size_t mActiveLayersEnd GUARDED_BY(mLock) = 0;
+
+ uint32_t mDisplayArea = 0;
+
+ // Whether to emit systrace output and debug logs.
+ const bool mTraceEnabled;
+
+ // Whether to use priority sent from WindowManager to determine the relevancy of the layer.
+ const bool mUseFrameRatePriority;
};
} // namespace impl
diff --git a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
new file mode 100644
index 0000000..a6d2c74
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
@@ -0,0 +1,206 @@
+/*
+ * 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LayerHistoryV2"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "LayerHistory.h"
+
+#include <cutils/properties.h>
+#include <utils/Log.h>
+#include <utils/Timers.h>
+#include <utils/Trace.h>
+
+#include <algorithm>
+#include <cmath>
+#include <string>
+#include <utility>
+
+#include "../Layer.h"
+#include "SchedulerUtils.h"
+
+#include "LayerInfoV2.h"
+
+namespace android::scheduler::impl {
+
+namespace {
+
+bool isLayerActive(const Layer& layer, const LayerInfoV2& info, nsecs_t threshold) {
+ if (layer.getFrameRate().has_value()) {
+ return layer.isVisible();
+ }
+ return layer.isVisible() && info.getLastUpdatedTime() >= threshold;
+}
+
+bool traceEnabled() {
+ return property_get_bool("debug.sf.layer_history_trace", false);
+}
+
+bool useFrameRatePriority() {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.sf.use_frame_rate_priority", value, "1");
+ return atoi(value);
+}
+
+void trace(const wp<Layer>& weak, LayerHistory::LayerVoteType type, int fps) {
+ const auto layer = weak.promote();
+ if (!layer) return;
+
+ const auto& name = layer->getName();
+ const auto noVoteTag = "LFPS NoVote " + name;
+ const auto heuristicVoteTag = "LFPS Heuristic " + name;
+ const auto explicitVoteTag = "LFPS Explicit " + name;
+ const auto minVoteTag = "LFPS Min " + name;
+ const auto maxVoteTag = "LFPS Max " + name;
+
+ ATRACE_INT(noVoteTag.c_str(), type == LayerHistory::LayerVoteType::NoVote ? 1 : 0);
+ ATRACE_INT(heuristicVoteTag.c_str(), type == LayerHistory::LayerVoteType::Heuristic ? fps : 0);
+ ATRACE_INT(explicitVoteTag.c_str(), type == LayerHistory::LayerVoteType::Explicit ? fps : 0);
+ ATRACE_INT(minVoteTag.c_str(), type == LayerHistory::LayerVoteType::Min ? 1 : 0);
+ ATRACE_INT(maxVoteTag.c_str(), type == LayerHistory::LayerVoteType::Max ? 1 : 0);
+
+ ALOGD("%s: %s @ %d Hz", __FUNCTION__, name.c_str(), fps);
+}
+
+} // namespace
+
+LayerHistoryV2::LayerHistoryV2()
+ : mTraceEnabled(traceEnabled()), mUseFrameRatePriority(useFrameRatePriority()) {}
+LayerHistoryV2::~LayerHistoryV2() = default;
+
+void LayerHistoryV2::registerLayer(Layer* layer, float /*lowRefreshRate*/, float highRefreshRate,
+ LayerVoteType type) {
+ const nsecs_t highRefreshRatePeriod = static_cast<nsecs_t>(1e9f / highRefreshRate);
+ auto info = std::make_unique<LayerInfoV2>(highRefreshRatePeriod, type);
+ std::lock_guard lock(mLock);
+ mLayerInfos.emplace_back(layer, std::move(info));
+}
+
+void LayerHistoryV2::record(Layer* layer, nsecs_t presentTime, nsecs_t now) {
+ std::lock_guard lock(mLock);
+
+ const auto it = std::find_if(mLayerInfos.begin(), mLayerInfos.end(),
+ [layer](const auto& pair) { return pair.first == layer; });
+ LOG_FATAL_IF(it == mLayerInfos.end(), "%s: unknown layer %p", __FUNCTION__, layer);
+
+ const auto& info = it->second;
+ info->setLastPresentTime(presentTime, now);
+
+ // Activate layer if inactive.
+ if (const auto end = activeLayers().end(); it >= end) {
+ std::iter_swap(it, end);
+ mActiveLayersEnd++;
+ }
+}
+
+LayerHistoryV2::Summary LayerHistoryV2::summarize(nsecs_t now) {
+ LayerHistory::Summary summary;
+
+ std::lock_guard lock(mLock);
+
+ partitionLayers(now);
+
+ for (const auto& [layer, info] : activeLayers()) {
+ const auto strong = layer.promote();
+ if (!strong) {
+ continue;
+ }
+
+ const bool recent = info->isRecentlyActive(now);
+ if (recent) {
+ const auto [type, refreshRate] = info->getRefreshRate(now);
+ // Skip NoVote layer as those don't have any requirements
+ if (type == LayerHistory::LayerVoteType::NoVote) {
+ continue;
+ }
+
+ // Compute the layer's position on the screen
+ const Rect bounds = Rect(strong->getBounds());
+ const ui::Transform transform = strong->getTransform();
+ constexpr bool roundOutwards = true;
+ Rect transformed = transform.transform(bounds, roundOutwards);
+
+ const float layerArea = transformed.getWidth() * transformed.getHeight();
+ float weight = mDisplayArea ? layerArea / mDisplayArea : 0.0f;
+ summary.push_back({strong->getName(), type, refreshRate, weight});
+
+ if (CC_UNLIKELY(mTraceEnabled)) {
+ trace(layer, type, static_cast<int>(std::round(refreshRate)));
+ }
+ } else if (CC_UNLIKELY(mTraceEnabled)) {
+ trace(layer, LayerHistory::LayerVoteType::NoVote, 0);
+ }
+ }
+
+ return summary;
+}
+
+void LayerHistoryV2::partitionLayers(nsecs_t now) {
+ const nsecs_t threshold = getActiveLayerThreshold(now);
+
+ // Collect expired and inactive layers after active layers.
+ size_t i = 0;
+ while (i < mActiveLayersEnd) {
+ auto& [weak, info] = mLayerInfos[i];
+ if (const auto layer = weak.promote(); layer && isLayerActive(*layer, *info, threshold)) {
+ i++;
+ // Set layer vote if set
+ const auto frameRate = layer->getFrameRate();
+ if (frameRate.has_value()) {
+ if (*frameRate == Layer::FRAME_RATE_NO_VOTE) {
+ info->setLayerVote(LayerVoteType::NoVote, 0.f);
+ } else {
+ info->setLayerVote(LayerVoteType::Explicit, *frameRate);
+ }
+ } else {
+ info->resetLayerVote();
+ }
+ continue;
+ }
+
+ if (CC_UNLIKELY(mTraceEnabled)) {
+ trace(weak, LayerHistory::LayerVoteType::NoVote, 0);
+ }
+
+ info->clearHistory();
+ std::swap(mLayerInfos[i], mLayerInfos[--mActiveLayersEnd]);
+ }
+
+ // Collect expired layers after inactive layers.
+ size_t end = mLayerInfos.size();
+ while (i < end) {
+ if (mLayerInfos[i].first.promote()) {
+ i++;
+ } else {
+ std::swap(mLayerInfos[i], mLayerInfos[--end]);
+ }
+ }
+
+ mLayerInfos.erase(mLayerInfos.begin() + static_cast<long>(end), mLayerInfos.end());
+}
+
+void LayerHistoryV2::clear() {
+ std::lock_guard lock(mLock);
+
+ for (const auto& [layer, info] : activeLayers()) {
+ info->clearHistory();
+ }
+
+ mActiveLayersEnd = 0;
+}
+
+} // namespace android::scheduler::impl
diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
new file mode 100644
index 0000000..d94d758
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ */
+
+// #define LOG_NDEBUG 0
+
+#include "LayerInfoV2.h"
+
+#include <algorithm>
+#include <utility>
+
+#undef LOG_TAG
+#define LOG_TAG "LayerInfoV2"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+namespace android::scheduler {
+
+LayerInfoV2::LayerInfoV2(nsecs_t highRefreshRatePeriod, LayerHistory::LayerVoteType defaultVote)
+ : mHighRefreshRatePeriod(highRefreshRatePeriod),
+ mDefaultVote(defaultVote),
+ mLayerVote({defaultVote, 0.0f}) {}
+
+void LayerInfoV2::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now) {
+ lastPresentTime = std::max(lastPresentTime, static_cast<nsecs_t>(0));
+
+ mLastUpdatedTime = std::max(lastPresentTime, now);
+
+ FrameTimeData frameTime = {.presetTime = lastPresentTime, .queueTime = mLastUpdatedTime};
+
+ mFrameTimes.push_back(frameTime);
+ if (mFrameTimes.size() > HISTORY_SIZE) {
+ mFrameTimes.pop_front();
+ }
+}
+
+// Returns whether the earliest present time is within the active threshold.
+bool LayerInfoV2::isRecentlyActive(nsecs_t now) const {
+ if (mFrameTimes.empty()) {
+ return false;
+ }
+
+ return mFrameTimes.back().queueTime >= getActiveLayerThreshold(now);
+}
+
+bool LayerInfoV2::isFrequent(nsecs_t now) const {
+ // Assume layer is infrequent if too few present times have been recorded.
+ if (mFrameTimes.size() < FREQUENT_LAYER_WINDOW_SIZE) {
+ return true;
+ }
+
+ // Layer is frequent if the earliest value in the window of most recent present times is
+ // within threshold.
+ const auto it = mFrameTimes.end() - FREQUENT_LAYER_WINDOW_SIZE;
+ const nsecs_t threshold = now - MAX_FREQUENT_LAYER_PERIOD_NS.count();
+ return it->queueTime >= threshold;
+}
+
+bool LayerInfoV2::hasEnoughDataForHeuristic() const {
+ // The layer had to publish at least HISTORY_SIZE or HISTORY_TIME of updates
+ if (mFrameTimes.size() < HISTORY_SIZE &&
+ mFrameTimes.back().queueTime - mFrameTimes.front().queueTime < HISTORY_TIME.count()) {
+ return false;
+ }
+
+ return true;
+}
+
+std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() {
+ static constexpr float MARGIN = 1.0f; // 1Hz
+
+ if (!hasEnoughDataForHeuristic()) {
+ ALOGV("Not enough data");
+ return std::nullopt;
+ }
+
+ // Calculate the refresh rate by finding the average delta between frames
+ nsecs_t totalPresentTimeDeltas = 0;
+ for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) {
+ // If there are no presentation timestamp provided we can't calculate the refresh rate
+ if (it->presetTime == 0 || (it + 1)->presetTime == 0) {
+ return std::nullopt;
+ }
+
+ totalPresentTimeDeltas +=
+ std::max(((it + 1)->presetTime - it->presetTime), mHighRefreshRatePeriod);
+ }
+ const float averageFrameTime =
+ static_cast<float>(totalPresentTimeDeltas) / (mFrameTimes.size() - 1);
+
+ // Now once we calculated the refresh rate we need to make sure that all the frames we captured
+ // are evenly distrubuted and we don't calculate the average across some burst of frames.
+
+ for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) {
+ const nsecs_t presentTimeDeltas =
+ std::max(((it + 1)->presetTime - it->presetTime), mHighRefreshRatePeriod);
+ if (std::abs(presentTimeDeltas - averageFrameTime) > 2 * averageFrameTime) {
+ return std::nullopt;
+ }
+ }
+
+ const auto refreshRate = 1e9f / averageFrameTime;
+ if (std::abs(refreshRate - mLastReportedRefreshRate) > MARGIN) {
+ mLastReportedRefreshRate = refreshRate;
+ }
+
+ ALOGV("Refresh rate: %.2f", mLastReportedRefreshRate);
+ return mLastReportedRefreshRate;
+}
+
+std::pair<LayerHistory::LayerVoteType, float> LayerInfoV2::getRefreshRate(nsecs_t now) {
+ if (mLayerVote.type != LayerHistory::LayerVoteType::Heuristic) {
+ return {mLayerVote.type, mLayerVote.fps};
+ }
+
+ if (!isFrequent(now)) {
+ return {LayerHistory::LayerVoteType::Min, 0};
+ }
+
+ auto refreshRate = calculateRefreshRateIfPossible();
+ if (refreshRate.has_value()) {
+ return {LayerHistory::LayerVoteType::Heuristic, refreshRate.value()};
+ }
+
+ return {LayerHistory::LayerVoteType::Max, 0};
+}
+
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.h b/services/surfaceflinger/Scheduler/LayerInfoV2.h
new file mode 100644
index 0000000..564f05e
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.h
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <utils/Timers.h>
+
+#include <chrono>
+#include <deque>
+
+#include "LayerHistory.h"
+#include "RefreshRateConfigs.h"
+#include "SchedulerUtils.h"
+
+namespace android {
+
+class Layer;
+
+namespace scheduler {
+
+using namespace std::chrono_literals;
+
+// Maximum period between presents for a layer to be considered active.
+constexpr std::chrono::nanoseconds MAX_ACTIVE_LAYER_PERIOD_NS = 1200ms;
+
+// Earliest present time for a layer to be considered active.
+constexpr nsecs_t getActiveLayerThreshold(nsecs_t now) {
+ return now - MAX_ACTIVE_LAYER_PERIOD_NS.count();
+}
+
+// Stores history of present times and refresh rates for a layer.
+class LayerInfoV2 {
+ // Layer is considered frequent if the earliest value in the window of most recent present times
+ // is within a threshold. If a layer is infrequent, its average refresh rate is disregarded in
+ // favor of a low refresh rate.
+ static constexpr size_t FREQUENT_LAYER_WINDOW_SIZE = 3;
+ static constexpr std::chrono::nanoseconds MAX_FREQUENT_LAYER_PERIOD_NS = 250ms;
+
+ friend class LayerHistoryTestV2;
+
+public:
+ LayerInfoV2(nsecs_t highRefreshRatePeriod, LayerHistory::LayerVoteType defaultVote);
+
+ LayerInfoV2(const LayerInfo&) = delete;
+ LayerInfoV2& operator=(const LayerInfoV2&) = delete;
+
+ // Records the last requested present time. It also stores information about when
+ // the layer was last updated. If the present time is farther in the future than the
+ // updated time, the updated time is the present time.
+ void setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now);
+
+ bool isRecentlyActive(nsecs_t now) const;
+
+ // Sets an explicit layer vote. This usually comes directly from the application via
+ // ANativeWindow_setFrameRate API
+ void setLayerVote(LayerHistory::LayerVoteType type, float fps) { mLayerVote = {type, fps}; }
+
+ // Sets the default layer vote. This will be the layer vote after calling to resetLayerVote().
+ // This is used for layers that called to setLayerVote() and then removed the vote, so that the
+ // layer can go back to whatever vote it had before the app voted for it.
+ void setDefaultLayerVote(LayerHistory::LayerVoteType type) { mDefaultVote = type; }
+
+ // Resets the layer vote to its default.
+ void resetLayerVote() { mLayerVote = {mDefaultVote, 0.0f}; }
+
+ std::pair<LayerHistory::LayerVoteType, float> getRefreshRate(nsecs_t now);
+
+ // Return the last updated time. If the present time is farther in the future than the
+ // updated time, the updated time is the present time.
+ nsecs_t getLastUpdatedTime() const { return mLastUpdatedTime; }
+
+ void clearHistory() { mFrameTimes.clear(); }
+
+private:
+ bool isFrequent(nsecs_t now) const;
+ bool hasEnoughDataForHeuristic() const;
+ std::optional<float> calculateRefreshRateIfPossible();
+
+ // Used for sanitizing the heuristic data
+ const nsecs_t mHighRefreshRatePeriod;
+ LayerHistory::LayerVoteType mDefaultVote;
+
+ nsecs_t mLastUpdatedTime = 0;
+
+ float mLastReportedRefreshRate = 0.0f;
+
+ // Holds information about the layer vote
+ struct {
+ LayerHistory::LayerVoteType type;
+ float fps;
+ } mLayerVote;
+
+ // Used to store the layer timestamps
+ struct FrameTimeData {
+ nsecs_t presetTime; // desiredPresentTime, if provided
+ nsecs_t queueTime; // buffer queue time
+ };
+ std::deque<FrameTimeData> mFrameTimes;
+ static constexpr size_t HISTORY_SIZE = 90;
+ static constexpr std::chrono::nanoseconds HISTORY_TIME = 1s;
+};
+
+} // namespace scheduler
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index 5318b00..005d157 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <errno.h>
#include <stdint.h>
#include <sys/types.h>
@@ -159,3 +163,6 @@
} // namespace impl
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
index 13014c7..63d9c4b 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
@@ -115,9 +115,9 @@
}
PhaseOffsets::Offsets PhaseOffsets::getHighFpsOffsets(nsecs_t vsyncDuration) const {
- const int highFpsLateAppOffsetNs =
+ const auto highFpsLateAppOffsetNs =
getProperty("debug.sf.high_fps_late_app_phase_offset_ns").value_or(2000000);
- const int highFpsLateSfOffsetNs =
+ const auto highFpsLateSfOffsetNs =
getProperty("debug.sf.high_fps_late_sf_phase_offset_ns").value_or(1000000);
const auto highFpsEarlySfOffsetNs = getProperty("debug.sf.high_fps_early_phase_offset_ns");
@@ -205,6 +205,32 @@
: vsyncDuration - (appDuration + sfDuration) % vsyncDuration;
}
+PhaseDurations::Offsets PhaseDurations::constructOffsets(nsecs_t vsyncDuration) const {
+ return Offsets{
+ {
+ mSfEarlyDuration < vsyncDuration
+ ? sfDurationToOffset(mSfEarlyDuration, vsyncDuration)
+ : sfDurationToOffset(mSfEarlyDuration, vsyncDuration) - vsyncDuration,
+
+ appDurationToOffset(mAppEarlyDuration, mSfEarlyDuration, vsyncDuration),
+ },
+ {
+ mSfEarlyGlDuration < vsyncDuration
+ ? sfDurationToOffset(mSfEarlyGlDuration, vsyncDuration)
+ : sfDurationToOffset(mSfEarlyGlDuration, vsyncDuration) - vsyncDuration,
+
+ appDurationToOffset(mAppEarlyGlDuration, mSfEarlyGlDuration, vsyncDuration),
+ },
+ {
+ mSfDuration < vsyncDuration
+ ? sfDurationToOffset(mSfDuration, vsyncDuration)
+ : sfDurationToOffset(mSfDuration, vsyncDuration) - vsyncDuration,
+
+ appDurationToOffset(mAppDuration, mSfDuration, vsyncDuration),
+ },
+ };
+}
+
static std::vector<float> getRefreshRatesFromConfigs(
const android::scheduler::RefreshRateConfigs& refreshRateConfigs) {
const auto& allRefreshRates = refreshRateConfigs.getAllRefreshRates();
@@ -223,41 +249,7 @@
std::unordered_map<float, Offsets> offsets;
for (const auto fps : refreshRates) {
- const nsecs_t vsyncDuration = static_cast<nsecs_t>(1e9f / fps);
- offsets.emplace(fps,
- Offsets{
- {
- mSfEarlyDuration < vsyncDuration
- ? sfDurationToOffset(mSfEarlyDuration,
- vsyncDuration)
- : sfDurationToOffset(mSfEarlyDuration,
- vsyncDuration) -
- vsyncDuration,
-
- appDurationToOffset(mAppEarlyDuration, mSfEarlyDuration,
- vsyncDuration),
- },
- {
- mSfEarlyGlDuration < vsyncDuration
- ? sfDurationToOffset(mSfEarlyGlDuration,
- vsyncDuration)
- : sfDurationToOffset(mSfEarlyGlDuration,
- vsyncDuration) -
- vsyncDuration,
-
- appDurationToOffset(mAppEarlyGlDuration, mSfEarlyGlDuration,
- vsyncDuration),
- },
- {
- mSfDuration < vsyncDuration
- ? sfDurationToOffset(mSfDuration, vsyncDuration)
- : sfDurationToOffset(mSfDuration, vsyncDuration) -
- vsyncDuration,
-
- appDurationToOffset(mAppDuration, mSfDuration,
- vsyncDuration),
- },
- });
+ offsets.emplace(fps, constructOffsets(static_cast<nsecs_t>(1e9f / fps)));
}
return offsets;
}
@@ -291,8 +283,16 @@
const auto iter = std::find_if(mOffsets.begin(), mOffsets.end(), [=](const auto& candidateFps) {
return fpsEqualsWithMargin(fps, candidateFps.first);
});
- LOG_ALWAYS_FATAL_IF(iter == mOffsets.end());
- return iter->second;
+
+ if (iter != mOffsets.end()) {
+ return iter->second;
+ }
+
+ // Unknown refresh rate. This might happen if we get a hotplug event for the default display.
+ // This happens only during tests and not during regular device operation.
+ // In this case just construct the offset.
+ ALOGW("Can't find offset for %.2f fps", fps);
+ return constructOffsets(static_cast<nsecs_t>(1e9f / fps));
}
void PhaseDurations::dump(std::string& result) const {
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.h b/services/surfaceflinger/Scheduler/PhaseOffsets.h
index 7b1bdfd..b7d4eae 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.h
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h
@@ -108,6 +108,7 @@
private:
std::unordered_map<float, Offsets> initializeOffsets(const std::vector<float>&) const;
+ PhaseDurations::Offsets constructOffsets(nsecs_t vsyncDuration) const;
const nsecs_t mSfDuration;
const nsecs_t mAppDuration;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 692ded9..c187049 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -15,19 +15,46 @@
*/
// #define LOG_NDEBUG 0
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
#include "RefreshRateConfigs.h"
+#include <android-base/stringprintf.h>
+#include <utils/Trace.h>
+#include <chrono>
+#include <cmath>
+
+using namespace std::chrono_literals;
namespace android::scheduler {
using AllRefreshRatesMapType = RefreshRateConfigs::AllRefreshRatesMapType;
using RefreshRate = RefreshRateConfigs::RefreshRate;
-// Returns the refresh rate map. This map won't be modified at runtime, so it's safe to access
-// from multiple threads. This can only be called if refreshRateSwitching() returns true.
-// TODO(b/122916473): Get this information from configs prepared by vendors, instead of
-// baking them in.
-const RefreshRate& RefreshRateConfigs::getRefreshRateForContent(float contentFramerate) const {
+const RefreshRate& RefreshRateConfigs::getRefreshRateForContent(
+ const std::vector<LayerRequirement>& layers) const {
std::lock_guard lock(mLock);
+ int contentFramerate = 0;
+ int explicitContentFramerate = 0;
+ for (const auto& layer : layers) {
+ const auto desiredRefreshRateRound = round<int>(layer.desiredRefreshRate);
+ if (layer.vote == LayerVoteType::Explicit) {
+ if (desiredRefreshRateRound > explicitContentFramerate) {
+ explicitContentFramerate = desiredRefreshRateRound;
+ }
+ } else {
+ if (desiredRefreshRateRound > contentFramerate) {
+ contentFramerate = desiredRefreshRateRound;
+ }
+ }
+ }
+
+ if (explicitContentFramerate != 0) {
+ contentFramerate = explicitContentFramerate;
+ } else if (contentFramerate == 0) {
+ contentFramerate = round<int>(mMaxSupportedRefreshRate->fps);
+ }
+ ATRACE_INT("ContentFPS", contentFramerate);
+
// Find the appropriate refresh rate with minimal error
auto iter = min_element(mAvailableRefreshRates.cbegin(), mAvailableRefreshRates.cend(),
[contentFramerate](const auto& lhs, const auto& rhs) -> bool {
@@ -56,6 +83,113 @@
return *bestSoFar;
}
+const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2(
+ const std::vector<LayerRequirement>& layers) const {
+ constexpr nsecs_t MARGIN = std::chrono::nanoseconds(800us).count();
+ ATRACE_CALL();
+ ALOGV("getRefreshRateForContent %zu layers", layers.size());
+
+ std::lock_guard lock(mLock);
+
+ int noVoteLayers = 0;
+ int minVoteLayers = 0;
+ int maxVoteLayers = 0;
+ int explicitVoteLayers = 0;
+ for (const auto& layer : layers) {
+ if (layer.vote == LayerVoteType::NoVote)
+ noVoteLayers++;
+ else if (layer.vote == LayerVoteType::Min)
+ minVoteLayers++;
+ else if (layer.vote == LayerVoteType::Max)
+ maxVoteLayers++;
+ else if (layer.vote == LayerVoteType::Explicit)
+ explicitVoteLayers++;
+ }
+
+ // Only if all layers want Min we should return Min
+ if (noVoteLayers + minVoteLayers == layers.size()) {
+ return *mAvailableRefreshRates.front();
+ }
+
+ // If we have some Max layers and no Explicit we should return Max
+ if (maxVoteLayers > 0 && explicitVoteLayers == 0) {
+ return *mAvailableRefreshRates.back();
+ }
+
+ // Find the best refresh rate based on score
+ std::vector<std::pair<const RefreshRate*, float>> scores;
+ scores.reserve(mAvailableRefreshRates.size());
+
+ for (const auto refreshRate : mAvailableRefreshRates) {
+ scores.emplace_back(refreshRate, 0.0f);
+ }
+
+ for (const auto& layer : layers) {
+ if (layer.vote == LayerVoteType::NoVote || layer.vote == LayerVoteType::Min ||
+ layer.vote == LayerVoteType::Max) {
+ continue;
+ }
+
+ // If we have Explicit layers, ignore the Huristic ones
+ if (explicitVoteLayers > 0 && layer.vote == LayerVoteType::Heuristic) {
+ continue;
+ }
+
+ for (auto& [refreshRate, overallScore] : scores) {
+ const auto displayPeriod = refreshRate->vsyncPeriod;
+ const auto layerPeriod = round<nsecs_t>(1e9f / layer.desiredRefreshRate);
+
+ // Calculate how many display vsyncs we need to present a single frame for this layer
+ auto [displayFramesQuot, displayFramesRem] = std::div(layerPeriod, displayPeriod);
+ if (displayFramesRem <= MARGIN ||
+ std::abs(displayFramesRem - displayPeriod) <= MARGIN) {
+ displayFramesQuot++;
+ displayFramesRem = 0;
+ }
+
+ float layerScore;
+ if (displayFramesRem == 0) {
+ // Layer desired refresh rate matches the display rate.
+ layerScore = layer.weight * 1.0f;
+ } else if (displayFramesQuot == 0) {
+ // Layer desired refresh rate is higher the display rate.
+ layerScore = layer.weight * layerPeriod / displayPeriod;
+ } else {
+ // Layer desired refresh rate is lower the display rate. Check how well it fits the
+ // cadence
+ auto diff = std::abs(displayFramesRem - (displayPeriod - displayFramesRem));
+ int iter = 2;
+ static constexpr size_t MAX_ITERATOR = 10; // Stop calculating when score < 0.1
+ while (diff > MARGIN && iter < MAX_ITERATOR) {
+ diff = diff - (displayPeriod - diff);
+ iter++;
+ }
+
+ layerScore = layer.weight * 1.0f / iter;
+ }
+
+ ALOGV("%s (weight %.2f) %.2fHz gives %s score of %.2f", layer.name.c_str(),
+ layer.weight, 1e9f / layerPeriod, refreshRate->name.c_str(), layerScore);
+ overallScore += layerScore;
+ }
+ }
+
+ float max = 0;
+ const RefreshRate* bestRefreshRate = nullptr;
+ for (const auto [refreshRate, score] : scores) {
+ ALOGV("%s scores %.2f", refreshRate->name.c_str(), score);
+
+ ATRACE_INT(refreshRate->name.c_str(), round<int>(score * 100));
+
+ if (score > max) {
+ max = score;
+ bestRefreshRate = refreshRate;
+ }
+ }
+
+ return bestRefreshRate == nullptr ? *mCurrentRefreshRate : *bestRefreshRate;
+}
+
const AllRefreshRatesMapType& RefreshRateConfigs::getAllRefreshRates() const {
return mRefreshRates;
}
@@ -101,11 +235,10 @@
HwcConfigIndexType currentConfigId)
: mRefreshRateSwitching(refreshRateSwitching) {
std::vector<InputConfig> inputConfigs;
- for (auto configId = HwcConfigIndexType(0); configId < HwcConfigIndexType(configs.size());
- ++configId) {
- auto configGroup = HwcConfigGroupType(configs[configId.value()]->getConfigGroup());
- inputConfigs.push_back(
- {configId, configGroup, configs[configId.value()]->getVsyncPeriod()});
+ for (size_t configId = 0; configId < configs.size(); ++configId) {
+ auto configGroup = HwcConfigGroupType(configs[configId]->getConfigGroup());
+ inputConfigs.push_back({HwcConfigIndexType(static_cast<int>(configId)), configGroup,
+ configs[configId]->getVsyncPeriod()});
}
init(inputConfigs, currentConfigId);
}
@@ -176,14 +309,21 @@
void RefreshRateConfigs::constructAvailableRefreshRates() {
// Filter configs based on current policy and sort based on vsync period
HwcConfigGroupType group = mRefreshRates.at(mDefaultConfig).configGroup;
- ALOGV("constructRefreshRateMap: default %d group %d min %.2f max %.2f", mDefaultConfig.value(),
- group.value(), mMinRefreshRateFps, mMaxRefreshRateFps);
+ ALOGV("constructAvailableRefreshRates: default %d group %d min %.2f max %.2f",
+ mDefaultConfig.value(), group.value(), mMinRefreshRateFps, mMaxRefreshRateFps);
getSortedRefreshRateList(
[&](const RefreshRate& refreshRate) REQUIRES(mLock) {
return refreshRate.configGroup == group &&
refreshRate.inPolicy(mMinRefreshRateFps, mMaxRefreshRateFps);
},
&mAvailableRefreshRates);
+
+ std::string availableRefreshRates;
+ for (const auto& refreshRate : mAvailableRefreshRates) {
+ base::StringAppendF(&availableRefreshRates, "%s ", refreshRate->name.c_str());
+ }
+
+ ALOGV("Available refresh rates: %s", availableRefreshRates.c_str());
LOG_ALWAYS_FATAL_IF(mAvailableRefreshRates.empty(),
"No compatible display configs for default=%d min=%.0f max=%.0f",
mDefaultConfig.value(), mMinRefreshRateFps, mMaxRefreshRateFps);
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 0c3369a..80d42cc 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -97,8 +97,39 @@
// Returns true if this device is doing refresh rate switching. This won't change at runtime.
bool refreshRateSwitchingSupported() const { return mRefreshRateSwitching; }
+ // Describes the different options the layer voted for refresh rate
+ enum class LayerVoteType {
+ NoVote, // Doesn't care about the refresh rate
+ Min, // Minimal refresh rate available
+ Max, // Maximal refresh rate available
+ Heuristic, // Specific refresh rate that was calculated by platform using a heuristic
+ Explicit, // Specific refresh rate that was provided by the app
+ };
+
+ // Captures the layer requirements for a refresh rate. This will be used to determine the
+ // display refresh rate.
+ struct LayerRequirement {
+ std::string name; // Layer's name. Used for debugging purposes.
+ LayerVoteType vote; // Layer vote type.
+ float desiredRefreshRate; // Layer's desired refresh rate, if applicable.
+ float weight; // Layer's weight in the range of [0, 1]. The higher the weight the more
+ // impact this layer would have on choosing the refresh rate.
+
+ bool operator==(const LayerRequirement& other) const {
+ return name == other.name && vote == other.vote &&
+ desiredRefreshRate == other.desiredRefreshRate && weight == other.weight;
+ }
+
+ bool operator!=(const LayerRequirement& other) const { return !(*this == other); }
+ };
+
// Returns all available refresh rates according to the current policy.
- const RefreshRate& getRefreshRateForContent(float contentFramerate) const EXCLUDES(mLock);
+ const RefreshRate& getRefreshRateForContent(const std::vector<LayerRequirement>& layers) const
+ EXCLUDES(mLock);
+
+ // Returns all available refresh rates according to the current policy.
+ const RefreshRate& getRefreshRateForContentV2(const std::vector<LayerRequirement>& layers) const
+ EXCLUDES(mLock);
// Returns all the refresh rates supported by the device. This won't change at runtime.
const AllRefreshRatesMapType& getAllRefreshRates() const EXCLUDES(mLock);
diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h
index a384dbe..e44cd52 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateStats.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h
@@ -114,7 +114,8 @@
mConfigModesTotalTime[mCurrentConfigMode] = 0;
}
mConfigModesTotalTime[mCurrentConfigMode] += timeElapsedMs;
- fps = mRefreshRateConfigs.getRefreshRateFromConfigId(mCurrentConfigMode).fps;
+ fps = static_cast<uint32_t>(std::round(
+ mRefreshRateConfigs.getRefreshRateFromConfigId(mCurrentConfigMode).fps));
} else {
mScreenOffTime += timeElapsedMs;
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 73dc753..7de35af 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -99,16 +99,21 @@
Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function,
const scheduler::RefreshRateConfigs& refreshRateConfig,
- ISchedulerCallback& schedulerCallback)
+ ISchedulerCallback& schedulerCallback, bool useContentDetectionV2)
: mPrimaryDispSync(createDispSync()),
mEventControlThread(new impl::EventControlThread(std::move(function))),
mSupportKernelTimer(sysprop::support_kernel_idle_timer(false)),
mSchedulerCallback(schedulerCallback),
- mRefreshRateConfigs(refreshRateConfig) {
+ mRefreshRateConfigs(refreshRateConfig),
+ mUseContentDetectionV2(useContentDetectionV2) {
using namespace sysprop;
if (property_get_bool("debug.sf.use_smart_90_for_video", 0) || use_smart_90_for_video(false)) {
- mLayerHistory = std::make_unique<scheduler::impl::LayerHistory>();
+ if (mUseContentDetectionV2) {
+ mLayerHistory = std::make_unique<scheduler::impl::LayerHistoryV2>();
+ } else {
+ mLayerHistory = std::make_unique<scheduler::impl::LayerHistory>();
+ }
}
const int setIdleTimerMs = property_get_int32("debug.sf.set_idle_timer_ms", 0);
@@ -116,7 +121,6 @@
if (const auto millis = setIdleTimerMs ? setIdleTimerMs : set_idle_timer_ms(0); millis > 0) {
const auto callback = mSupportKernelTimer ? &Scheduler::kernelIdleTimerCallback
: &Scheduler::idleTimerCallback;
-
mIdleTimer.emplace(
std::chrono::milliseconds(millis),
[this, callback] { std::invoke(callback, this, TimerState::Reset); },
@@ -145,12 +149,13 @@
Scheduler::Scheduler(std::unique_ptr<DispSync> primaryDispSync,
std::unique_ptr<EventControlThread> eventControlThread,
const scheduler::RefreshRateConfigs& configs,
- ISchedulerCallback& schedulerCallback)
+ ISchedulerCallback& schedulerCallback, bool useContentDetectionV2)
: mPrimaryDispSync(std::move(primaryDispSync)),
mEventControlThread(std::move(eventControlThread)),
mSupportKernelTimer(false),
mSchedulerCallback(schedulerCallback),
- mRefreshRateConfigs(configs) {}
+ mRefreshRateConfigs(configs),
+ mUseContentDetectionV2(useContentDetectionV2) {}
Scheduler::~Scheduler() {
// Ensure the OneShotTimer threads are joined before we start destroying state.
@@ -371,12 +376,42 @@
void Scheduler::registerLayer(Layer* layer) {
if (!mLayerHistory) return;
- const auto lowFps = mRefreshRateConfigs.getMinRefreshRate().fps;
- const auto highFps = layer->getWindowType() == InputWindowInfo::TYPE_WALLPAPER
- ? lowFps
- : mRefreshRateConfigs.getMaxRefreshRate().fps;
+ if (!mUseContentDetectionV2) {
+ const auto lowFps = mRefreshRateConfigs.getMinRefreshRate().fps;
+ const auto highFps = layer->getWindowType() == InputWindowInfo::TYPE_WALLPAPER
+ ? lowFps
+ : mRefreshRateConfigs.getMaxRefreshRate().fps;
- mLayerHistory->registerLayer(layer, lowFps, highFps);
+ mLayerHistory->registerLayer(layer, lowFps, highFps,
+ scheduler::LayerHistory::LayerVoteType::Heuristic);
+ } else {
+ if (layer->getWindowType() == InputWindowInfo::TYPE_WALLPAPER) {
+ mLayerHistory->registerLayer(layer, mRefreshRateConfigs.getMinRefreshRate().fps,
+ mRefreshRateConfigs.getMaxRefreshRate().fps,
+ scheduler::LayerHistory::LayerVoteType::Min);
+ } else if (layer->getWindowType() == InputWindowInfo::TYPE_STATUS_BAR) {
+ mLayerHistory->registerLayer(layer, mRefreshRateConfigs.getMinRefreshRate().fps,
+ mRefreshRateConfigs.getMaxRefreshRate().fps,
+ scheduler::LayerHistory::LayerVoteType::NoVote);
+ } else {
+ mLayerHistory->registerLayer(layer, mRefreshRateConfigs.getMinRefreshRate().fps,
+ mRefreshRateConfigs.getMaxRefreshRate().fps,
+ scheduler::LayerHistory::LayerVoteType::Heuristic);
+ }
+
+ // TODO(146935143): Simulate youtube app vote. This should be removed once youtube calls the
+ // API to set desired rate
+ {
+ const auto vote = property_get_int32("experimental.sf.force_youtube_vote", 0);
+ if (vote != 0 &&
+ layer->getName() ==
+ "SurfaceView - "
+ "com.google.android.youtube/"
+ "com.google.android.apps.youtube.app.WatchWhileActivity#0") {
+ layer->setFrameRate(vote);
+ }
+ }
+ }
}
void Scheduler::recordLayerHistory(Layer* layer, nsecs_t presentTime) {
@@ -388,27 +423,27 @@
void Scheduler::chooseRefreshRateForContent() {
if (!mLayerHistory) return;
- auto [refreshRate] = mLayerHistory->summarize(systemTime());
- const uint32_t refreshRateRound = std::round(refreshRate);
+ ATRACE_CALL();
+
+ scheduler::LayerHistory::Summary summary = mLayerHistory->summarize(systemTime());
HwcConfigIndexType newConfigId;
{
std::lock_guard<std::mutex> lock(mFeatureStateLock);
- if (mFeatures.contentRefreshRate == refreshRateRound) {
+ if (mFeatures.contentRequirements == summary) {
return;
}
- mFeatures.contentRefreshRate = refreshRateRound;
- ATRACE_INT("ContentFPS", refreshRateRound);
-
+ mFeatures.contentRequirements = summary;
mFeatures.contentDetection =
- refreshRateRound > 0 ? ContentDetectionState::On : ContentDetectionState::Off;
+ !summary.empty() ? ContentDetectionState::On : ContentDetectionState::Off;
+
newConfigId = calculateRefreshRateType();
if (mFeatures.configId == newConfigId) {
return;
}
mFeatures.configId = newConfigId;
- };
- auto newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId);
- mSchedulerCallback.changeRefreshRate(newRefreshRate, ConfigEvent::Changed);
+ auto newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId);
+ mSchedulerCallback.changeRefreshRate(newRefreshRate, ConfigEvent::Changed);
+ }
}
void Scheduler::resetIdleTimer() {
@@ -418,18 +453,21 @@
}
void Scheduler::notifyTouchEvent() {
- if (mTouchTimer) {
- mTouchTimer->reset();
- }
-
- if (mSupportKernelTimer && mIdleTimer) {
- mIdleTimer->reset();
- }
+ if (!mTouchTimer) return;
// Touch event will boost the refresh rate to performance.
- // Clear Layer History to get fresh FPS detection
- if (mLayerHistory) {
+ // Clear Layer History to get fresh FPS detection.
+ // NOTE: Instead of checking all the layers, we should be checking the layer
+ // that is currently on top. b/142507166 will give us this capability.
+ std::lock_guard<std::mutex> lock(mFeatureStateLock);
+ if (mLayerHistory && !layerHistoryHasClientSpecifiedFrameRate()) {
mLayerHistory->clear();
+
+ mTouchTimer->reset();
+
+ if (mSupportKernelTimer && mIdleTimer) {
+ mIdleTimer->reset();
+ }
}
}
@@ -524,36 +562,61 @@
mSchedulerCallback.changeRefreshRate(newRefreshRate, event);
}
+bool Scheduler::layerHistoryHasClientSpecifiedFrameRate() {
+ for (const auto& layer : mFeatures.contentRequirements) {
+ if (layer.vote == scheduler::RefreshRateConfigs::LayerVoteType::Explicit) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
HwcConfigIndexType Scheduler::calculateRefreshRateType() {
if (!mRefreshRateConfigs.refreshRateSwitchingSupported()) {
return mRefreshRateConfigs.getCurrentRefreshRate().configId;
}
- // If Display Power is not in normal operation we want to be in performance mode.
- // When coming back to normal mode, a grace period is given with DisplayPowerTimer
- if (!mFeatures.isDisplayPowerStateNormal || mFeatures.displayPowerTimer == TimerState::Reset) {
- return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
+ // If the layer history doesn't have the frame rate specified, use the old path. NOTE:
+ // if we remove the kernel idle timer, and use our internal idle timer, this code will have to
+ // be refactored.
+ if (!layerHistoryHasClientSpecifiedFrameRate()) {
+ // If Display Power is not in normal operation we want to be in performance mode.
+ // When coming back to normal mode, a grace period is given with DisplayPowerTimer
+ if (!mFeatures.isDisplayPowerStateNormal ||
+ mFeatures.displayPowerTimer == TimerState::Reset) {
+ return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
+ }
+
+ // As long as touch is active we want to be in performance mode
+ if (mFeatures.touch == TouchState::Active) {
+ return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
+ }
+
+ // If timer has expired as it means there is no new content on the screen
+ if (mFeatures.idleTimer == TimerState::Expired) {
+ return mRefreshRateConfigs.getMinRefreshRateByPolicy().configId;
+ }
}
- // As long as touch is active we want to be in performance mode
- if (mFeatures.touch == TouchState::Active) {
- return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
- }
+ if (!mUseContentDetectionV2) {
+ // If content detection is off we choose performance as we don't know the content fps
+ if (mFeatures.contentDetection == ContentDetectionState::Off) {
+ return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
+ }
- // If timer has expired as it means there is no new content on the screen
- if (mFeatures.idleTimer == TimerState::Expired) {
- return mRefreshRateConfigs.getMinRefreshRateByPolicy().configId;
- }
-
- // If content detection is off we choose performance as we don't know the content fps
- if (mFeatures.contentDetection == ContentDetectionState::Off) {
- return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
+ // Content detection is on, find the appropriate refresh rate with minimal error
+ return mRefreshRateConfigs.getRefreshRateForContent(mFeatures.contentRequirements).configId;
}
// Content detection is on, find the appropriate refresh rate with minimal error
- return mRefreshRateConfigs
- .getRefreshRateForContent(static_cast<float>(mFeatures.contentRefreshRate))
- .configId;
+ if (mFeatures.contentDetection == ContentDetectionState::On) {
+ return mRefreshRateConfigs.getRefreshRateForContentV2(mFeatures.contentRequirements)
+ .configId;
+ }
+
+ // There are no signals for refresh rate, just leave it as is
+ return mRefreshRateConfigs.getCurrentRefreshRate().configId;
}
std::optional<HwcConfigIndexType> Scheduler::getPreferredConfigId() {
@@ -594,4 +657,10 @@
}
}
+void Scheduler::onPrimaryDisplayAreaChanged(uint32_t displayArea) {
+ if (mLayerHistory) {
+ mLayerHistory->setDisplayArea(displayArea);
+ }
+}
+
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index c6430c3..01062f8 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -23,7 +23,11 @@
#include <optional>
#include <unordered_map>
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
#include <ui/GraphicTypes.h>
+#pragma clang diagnostic pop
#include "EventControlThread.h"
#include "EventThread.h"
@@ -58,7 +62,8 @@
enum class TransactionStart { EARLY, NORMAL };
Scheduler(impl::EventControlThread::SetVSyncEnabledFunction,
- const scheduler::RefreshRateConfigs&, ISchedulerCallback& schedulerCallback);
+ const scheduler::RefreshRateConfigs&, ISchedulerCallback& schedulerCallback,
+ bool useContentDetectionV2);
virtual ~Scheduler();
@@ -136,6 +141,9 @@
// Notifies the scheduler when the display was refreshed
void onDisplayRefreshed(nsecs_t timestamp);
+ // Notifies the scheduler when the display size has changed. Called from SF's main thread
+ void onPrimaryDisplayAreaChanged(uint32_t displayArea);
+
private:
friend class TestableScheduler;
@@ -147,7 +155,8 @@
// Used by tests to inject mocks.
Scheduler(std::unique_ptr<DispSync>, std::unique_ptr<EventControlThread>,
- const scheduler::RefreshRateConfigs&, ISchedulerCallback& schedulerCallback);
+ const scheduler::RefreshRateConfigs&, ISchedulerCallback& schedulerCallback,
+ bool useContentDetectionV2);
std::unique_ptr<VSyncSource> makePrimaryDispSyncSource(const char* name, nsecs_t phaseOffsetNs);
@@ -170,6 +179,8 @@
HwcConfigIndexType calculateRefreshRateType() REQUIRES(mFeatureStateLock);
+ bool layerHistoryHasClientSpecifiedFrameRate() REQUIRES(mFeatureStateLock);
+
// Stores EventThread associated with a given VSyncSource, and an initial EventThreadConnection.
struct Connection {
sp<EventThreadConnection> connection;
@@ -218,7 +229,7 @@
TimerState displayPowerTimer = TimerState::Expired;
std::optional<HwcConfigIndexType> configId;
- uint32_t contentRefreshRate = 0;
+ scheduler::LayerHistory::Summary contentRequirements;
bool isDisplayPowerStateNormal = true;
} mFeatures GUARDED_BY(mFeatureStateLock);
@@ -229,6 +240,8 @@
std::optional<HWC2::VsyncPeriodChangeTimeline> mLastVsyncPeriodChangeTimeline
GUARDED_BY(mVsyncTimelineLock);
static constexpr std::chrono::nanoseconds MAX_VSYNC_APPLIED_TIME = 200ms;
+
+ const bool mUseContentDetectionV2;
};
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/SchedulerUtils.cpp b/services/surfaceflinger/Scheduler/SchedulerUtils.cpp
index fb5414f..e8e0444 100644
--- a/services/surfaceflinger/Scheduler/SchedulerUtils.cpp
+++ b/services/surfaceflinger/Scheduler/SchedulerUtils.cpp
@@ -30,9 +30,10 @@
}
size_t n = v->size() / 2;
- nth_element(v->begin(), v->begin() + n, v->end());
+ nth_element(v->begin(), v->begin() + static_cast<long>(n), v->end());
return v->at(n);
}
} // namespace scheduler
} // namespace android
+
diff --git a/services/surfaceflinger/Scheduler/SchedulerUtils.h b/services/surfaceflinger/Scheduler/SchedulerUtils.h
index d301b99..04a4cd1 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,18 @@
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;
+
+template <typename T>
+static inline T round(float f) {
+ return static_cast<T>(std::round(f));
+}
+
} // 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/VSyncModulator.cpp b/services/surfaceflinger/Scheduler/VSyncModulator.cpp
index 8de35b1..40a992c 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include "VSyncModulator.h"
@@ -144,3 +148,6 @@
}
} // namespace android::scheduler
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index 3b99a58..ac32633 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -14,31 +14,42 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
//#define LOG_NDEBUG 0
#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) {
- mRateMap[mIdealPeriod] = {idealPeriod, 0};
+ 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 {
@@ -64,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;
}
@@ -110,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;
}
@@ -136,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,
@@ -148,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;
@@ -160,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 << " (+"
@@ -199,6 +220,10 @@
mRateMap[mIdealPeriod] = {period, 0};
}
+ clearTimestamps();
+}
+
+void VSyncPredictor::clearTimestamps() {
if (!timestamps.empty()) {
mKnownTimestamp = *std::max_element(timestamps.begin(), timestamps.end());
timestamps.clear();
@@ -219,8 +244,17 @@
}
}
- ATRACE_INT(kNeedsSamplesTag, needsMoreSamples);
+ ATRACE_INT("VSP-moreSamples", needsMoreSamples);
return needsMoreSamples;
}
+void VSyncPredictor::resetModel() {
+ std::lock_guard<std::mutex> lk(mMutex);
+ mRateMap[mIdealPeriod] = {mIdealPeriod, 0};
+ clearTimestamps();
+}
+
} // namespace android::scheduler
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h
index 4210b3c..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 {
@@ -40,6 +41,7 @@
void addVsyncTimestamp(nsecs_t timestamp) final;
nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const final;
nsecs_t currentPeriod() const final;
+ void resetModel() final;
/*
* Inform the model that the period is anticipated to change to a new value.
@@ -48,7 +50,7 @@
*
* \param [in] period The new period that should be used.
*/
- void setPeriod(nsecs_t period);
+ void setPeriod(nsecs_t period) final;
/* Query if the model is in need of more samples to make a prediction at timePoint.
* \param [in] timePoint The timePoint to inquire of.
@@ -61,6 +63,10 @@
private:
VSyncPredictor(VSyncPredictor const&) = delete;
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;
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
index 20b6238..53fa212 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
@@ -14,11 +14,13 @@
* limitations under the License.
*/
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#undef LOG_TAG
#define LOG_TAG "VSyncReactor"
//#define LOG_NDEBUG 0
#include "VSyncReactor.h"
#include <log/log.h>
+#include <utils/Trace.h>
#include "TimeKeeper.h"
#include "VSyncDispatch.h"
#include "VSyncTracker.h"
@@ -186,6 +188,7 @@
}
void VSyncReactor::setPeriod(nsecs_t period) {
+ ATRACE_INT64("VSR-setPeriod", period);
std::lock_guard lk(mMutex);
mLastHwVsync.reset();
if (period == getPeriod()) {
@@ -199,7 +202,9 @@
return mTracker->currentPeriod();
}
-void VSyncReactor::beginResync() {}
+void VSyncReactor::beginResync() {
+ mTracker->resetModel();
+}
void VSyncReactor::endResync() {}
diff --git a/services/surfaceflinger/Scheduler/VSyncTracker.h b/services/surfaceflinger/Scheduler/VSyncTracker.h
index 6be63fe..2b27884 100644
--- a/services/surfaceflinger/Scheduler/VSyncTracker.h
+++ b/services/surfaceflinger/Scheduler/VSyncTracker.h
@@ -61,6 +61,9 @@
*/
virtual void setPeriod(nsecs_t period) = 0;
+ /* Inform the tracker that the samples it has are not accurate for prediction. */
+ virtual void resetModel() = 0;
+
protected:
VSyncTracker(VSyncTracker const&) = delete;
VSyncTracker& operator=(VSyncTracker const&) = delete;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index b7a2c76..62d47e1 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
//#define LOG_NDEBUG 0
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
@@ -334,6 +338,14 @@
mLayerTripleBufferingDisabled = atoi(value);
ALOGI_IF(mLayerTripleBufferingDisabled, "Disabling Triple Buffering");
+ property_get("ro.surface_flinger.supports_background_blur", value, "0");
+ bool supportsBlurs = atoi(value);
+ property_get("debug.sf.disableBlurs", value, "0");
+ bool disableBlurs = atoi(value);
+ mEnableBlurs = supportsBlurs && !disableBlurs;
+ ALOGI_IF(!mEnableBlurs, "Disabling blur effects. supported: %d, disabled: %d", supportsBlurs,
+ disableBlurs);
+
const size_t defaultListSize = MAX_LAYERS;
auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize));
mMaxGraphicBufferProducerListSize = (listSize > 0) ? size_t(listSize) : defaultListSize;
@@ -341,6 +353,9 @@
property_get("debug.sf.luma_sampling", value, "1");
mLumaSampling = atoi(value);
+ property_get("debug.sf.disable_client_composition_cache", value, "0");
+ 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
@@ -490,6 +505,7 @@
ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
mFrameTracer->initialize();
+ mTimeStats->onBootFinished();
// wait patiently for the window manager death
const String16 name("window");
@@ -527,6 +543,11 @@
const auto& performanceRefreshRate = mRefreshRateConfigs->getMaxRefreshRateByPolicy();
changeRefreshRateLocked(performanceRefreshRate, Scheduler::ConfigEvent::None);
}
+
+ if (property_get_bool("sf.debug.show_refresh_rate_overlay", false)) {
+ mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(*this);
+ mRefreshRateOverlay->changeRefreshRate(mRefreshRateConfigs->getCurrentRefreshRate());
+ }
}));
}
@@ -576,6 +597,7 @@
.setUseColorManagerment(useColorManagement)
.setEnableProtectedContext(enable_protected_contents(false))
.setPrecacheToneMapperShaderOnly(false)
+ .setSupportsBackgroundBlur(mEnableBlurs)
.setContextPriority(useContextPriority
? renderengine::RenderEngine::ContextPriority::HIGH
: renderengine::RenderEngine::ContextPriority::MEDIUM)
@@ -871,7 +893,7 @@
repaintEverythingForHWC();
// Start receiving vsync samples now, so that we can detect a period
// switch.
- mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
+ mScheduler->resyncToHardwareVsync(true, refreshRate.vsyncPeriod);
// As we called to set period, we will call to onRefreshRateChangeCompleted once
// DispSync model is locked.
mVSyncModulator->onRefreshRateChangeInitiated();
@@ -948,9 +970,9 @@
mDesiredActiveConfig.event = Scheduler::ConfigEvent::None;
mDesiredActiveConfigChanged = false;
- mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
- auto refreshRate =
+ auto const refreshRate =
mRefreshRateConfigs->getRefreshRateFromConfigId(mDesiredActiveConfig.configId);
+ mScheduler->resyncToHardwareVsync(true, refreshRate.vsyncPeriod);
mPhaseConfiguration->setRefreshRateFps(refreshRate.fps);
mVSyncModulator->setPhaseOffsets(mPhaseConfiguration->getCurrentOffsets());
}
@@ -1747,12 +1769,6 @@
mGpuFrameMissedCount++;
}
- mScheduler->chooseRefreshRateForContent();
-
- if (performSetActiveConfig()) {
- break;
- }
-
if (frameMissed && mPropagateBackpressure) {
if ((hwcFrameMissed && !gpuFrameMissed) ||
mPropagateBackpressureClientComposition) {
@@ -1769,6 +1785,19 @@
bool refreshNeeded = handleMessageTransaction();
refreshNeeded |= handleMessageInvalidate();
+ // Layers need to get updated (in the previous line) before we can use them for
+ // choosing the refresh rate.
+ // Hold mStateLock as chooseRefreshRateForContent promotes wp<Layer> to sp<Layer>
+ // and may eventually call to ~Layer() if it holds the last reference
+ {
+ Mutex::Autolock _l(mStateLock);
+ mScheduler->chooseRefreshRateForContent();
+ }
+
+ if (performSetActiveConfig()) {
+ break;
+ }
+
updateCursorAsync();
updateInputFlinger();
@@ -1878,13 +1907,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);
@@ -2064,6 +2099,10 @@
mTimeStats->incrementClientCompositionFrames();
}
+ if (mReusedClientComposition) {
+ mTimeStats->incrementClientCompositionReusedFrames();
+ }
+
mTimeStats->setPresentFenceGlobal(presentFenceTime);
if (displayDevice && getHwComposer().isConnected(*displayDevice->getId()) &&
@@ -2363,6 +2402,9 @@
}
if (state.width != draw[i].width || state.height != draw[i].height) {
display->setDisplaySize(state.width, state.height);
+ if (display->isPrimary()) {
+ mScheduler->onPrimaryDisplayAreaChanged(state.width * state.height);
+ }
}
}
}
@@ -2435,6 +2477,12 @@
LOG_ALWAYS_FATAL_IF(!displayId);
dispatchDisplayHotplugEvent(displayId->value, true);
}
+
+ const auto displayDevice = mDisplays[displayToken];
+ if (displayDevice->isPrimary()) {
+ mScheduler->onPrimaryDisplayAreaChanged(displayDevice->getWidth() *
+ displayDevice->getHeight());
+ }
}
}
}
@@ -2632,8 +2680,12 @@
}
void SurfaceFlinger::changeRefreshRate(const RefreshRate& refreshRate,
- Scheduler::ConfigEvent event) {
- Mutex::Autolock lock(mStateLock);
+ Scheduler::ConfigEvent event) NO_THREAD_SAFETY_ANALYSIS {
+ // If this is called from the main thread mStateLock must be locked before
+ // Currently the only way to call this function from the main thread is from
+ // Sheduler::chooseRefreshRateForContent
+
+ ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
changeRefreshRateLocked(refreshRate, event);
}
@@ -3374,6 +3426,9 @@
if (layer->setCornerRadius(s.cornerRadius))
flags |= eTraversalNeeded;
}
+ if (what & layer_state_t::eBackgroundBlurRadiusChanged) {
+ if (layer->setBackgroundBlurRadius(s.backgroundBlurRadius)) flags |= eTraversalNeeded;
+ }
if (what & layer_state_t::eLayerStackChanged) {
ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
// We only allow setting layer stacks for top level layers,
@@ -3474,6 +3529,14 @@
if (what & layer_state_t::eShadowRadiusChanged) {
if (layer->setShadowRadius(s.shadowRadius)) flags |= eTraversalNeeded;
}
+ if (what & layer_state_t::eFrameRateSelectionPriority) {
+ if (privileged && layer->setFrameRateSelectionPriority(s.frameRateSelectionPriority)) {
+ flags |= eTraversalNeeded;
+ }
+ }
+ if (what & layer_state_t::eFrameRateChanged) {
+ if (layer->setFrameRate(s.frameRate)) flags |= eTraversalNeeded;
+ }
// This has to happen after we reparent children because when we reparent to null we remove
// child layers from current state and remove its relative z. If the children are reparented in
// the same transaction, then we have to make sure we reparent the children first so we do not
@@ -4507,7 +4570,6 @@
case ENABLE_VSYNC_INJECTIONS:
case GET_ANIMATION_FRAME_STATS:
case GET_HDR_CAPABILITIES:
- case SET_ACTIVE_CONFIG:
case SET_DESIRED_DISPLAY_CONFIG_SPECS:
case GET_DESIRED_DISPLAY_CONFIG_SPECS:
case SET_ACTIVE_COLOR_MODE:
@@ -5383,7 +5445,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.
@@ -5444,7 +5506,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);
@@ -5465,7 +5527,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) {
@@ -5475,13 +5537,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();
@@ -5575,11 +5644,10 @@
repaintEverythingForHWC();
}
- auto configId = HwcConfigIndexType(defaultConfig);
- display->setActiveConfig(configId);
+ display->setActiveConfig(defaultConfig);
const nsecs_t vsyncPeriod =
- mRefreshRateConfigs->getRefreshRateFromConfigId(configId).vsyncPeriod;
- mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value, configId,
+ getHwComposer().getConfigs(*displayId)[defaultConfig.value()]->getVsyncPeriod();
+ mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value, defaultConfig,
vsyncPeriod);
return NO_ERROR;
}
@@ -5772,3 +5840,6 @@
#if defined(__gl2_h_)
#error "don't include gl2/gl2.h in this file"
#endif
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 723e332..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;
@@ -445,7 +449,6 @@
bool* outSupported) const override;
void setGameContentType(const sp<IBinder>& displayToken, bool on) override;
void setPowerMode(const sp<IBinder>& displayToken, int mode) override;
- status_t setActiveConfig(const sp<IBinder>& displayToken, int id) override;
status_t clearAnimationFrameStats() override;
status_t getAnimationFrameStats(FrameStats* outStats) const override;
status_t getHdrCapabilities(const sp<IBinder>& displayToken,
@@ -538,6 +541,7 @@
void onInitializeDisplays() REQUIRES(mStateLock);
// Sets the desired active config bit. It obtains the lock, and sets mDesiredActiveConfig.
void setDesiredActiveConfig(const ActiveConfigInfo& info) REQUIRES(mStateLock);
+ status_t setActiveConfig(const sp<IBinder>& displayToken, int id);
// Once HWC has returned the present fence, this sets the active config and a new refresh
// rate in SF.
void setActiveConfigInternal() REQUIRES(mStateLock);
@@ -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,
@@ -1025,6 +1033,7 @@
const std::shared_ptr<TimeStats> mTimeStats;
const std::unique_ptr<FrameTracer> mFrameTracer;
bool mUseHwcVirtualDisplays = false;
+ bool mEnableBlurs = false;
std::atomic<uint32_t> mFrameMissedCount = 0;
std::atomic<uint32_t> mHwcFrameMissedCount = 0;
std::atomic<uint32_t> mGpuFrameMissedCount = 0;
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
index d5c2306..45889a5 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <compositionengine/impl/CompositionEngine.h>
#include <cutils/properties.h>
#include <ui/GraphicBuffer.h>
@@ -71,7 +75,9 @@
std::unique_ptr<Scheduler> DefaultFactory::createScheduler(
SetVSyncEnabled setVSyncEnabled, const scheduler::RefreshRateConfigs& configs,
ISchedulerCallback& schedulerCallback) {
- return std::make_unique<Scheduler>(std::move(setVSyncEnabled), configs, schedulerCallback);
+ return std::make_unique<Scheduler>(std::move(setVSyncEnabled), configs, schedulerCallback,
+ property_get_bool("debug.sf.use_content_detection_v2",
+ false));
}
std::unique_ptr<SurfaceInterceptor> DefaultFactory::createSurfaceInterceptor(
@@ -138,3 +144,6 @@
}
} // namespace android::surfaceflinger
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.cpp b/services/surfaceflinger/SurfaceFlingerFactory.cpp
index 9b1f658..3997b04 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerFactory.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include "SurfaceFlinger.h"
#include "SurfaceFlingerDefaultFactory.h"
@@ -26,3 +30,6 @@
}
} // namespace android::surfaceflinger
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 8e0462a..6884b4c 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -13,6 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
#undef LOG_TAG
#define LOG_TAG "SurfaceInterceptor"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
@@ -110,6 +114,7 @@
addLayerStackLocked(transaction, layerId, layer->mCurrentState.layerStack);
addCropLocked(transaction, layerId, layer->mCurrentState.crop_legacy);
addCornerRadiusLocked(transaction, layerId, layer->mCurrentState.cornerRadius);
+ addBackgroundBlurRadiusLocked(transaction, layerId, layer->mCurrentState.backgroundBlurRadius);
if (layer->mCurrentState.barrierLayer_legacy != nullptr) {
addDeferTransactionLocked(transaction, layerId,
layer->mCurrentState.barrierLayer_legacy.promote(),
@@ -318,6 +323,13 @@
cornerRadiusChange->set_corner_radius(cornerRadius);
}
+void SurfaceInterceptor::addBackgroundBlurRadiusLocked(Transaction* transaction, int32_t layerId,
+ int32_t backgroundBlurRadius) {
+ SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
+ BackgroundBlurRadiusChange* blurRadiusChange(change->mutable_background_blur_radius());
+ blurRadiusChange->set_background_blur_radius(backgroundBlurRadius);
+}
+
void SurfaceInterceptor::addDeferTransactionLocked(Transaction* transaction, int32_t layerId,
const sp<const Layer>& layer, uint64_t frameNumber)
{
@@ -418,6 +430,9 @@
if (state.what & layer_state_t::eCornerRadiusChanged) {
addCornerRadiusLocked(transaction, layerId, state.cornerRadius);
}
+ if (state.what & layer_state_t::eBackgroundBlurRadiusChanged) {
+ addBackgroundBlurRadiusLocked(transaction, layerId, state.backgroundBlurRadius);
+ }
if (state.what & layer_state_t::eDeferTransaction_legacy) {
sp<Layer> otherLayer = nullptr;
if (state.barrierHandle_legacy != nullptr) {
@@ -677,3 +692,6 @@
} // namespace impl
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
index c6f9e8a..a665f62 100644
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -152,6 +152,8 @@
void addLayerStackLocked(Transaction* transaction, int32_t layerId, uint32_t layerStack);
void addCropLocked(Transaction* transaction, int32_t layerId, const Rect& rect);
void addCornerRadiusLocked(Transaction* transaction, int32_t layerId, float cornerRadius);
+ void addBackgroundBlurRadiusLocked(Transaction* transaction, int32_t layerId,
+ int32_t backgroundBlurRadius);
void addDeferTransactionLocked(Transaction* transaction, int32_t layerId,
const sp<const Layer>& layer, uint64_t frameNumber);
void addOverrideScalingModeLocked(Transaction* transaction, int32_t layerId,
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
index eb26cd0..eb5c7de 100644
--- a/services/surfaceflinger/SurfaceTracing.cpp
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -13,6 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
#undef LOG_TAG
#define LOG_TAG "SurfaceTracing"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
@@ -184,8 +188,11 @@
ALOGE("Could not save the proto file! Permission denied");
mLastErr = PERMISSION_DENIED;
}
- if (!android::base::WriteStringToFile(output, kDefaultFileName, S_IRWXU | S_IRGRP, getuid(),
- getgid(), true)) {
+
+ // -rw-r--r--
+ const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+ if (!android::base::WriteStringToFile(output, kDefaultFileName, mode, getuid(), getgid(),
+ true)) {
ALOGE("Could not save the proto file! There are missing fields");
mLastErr = PERMISSION_DENIED;
}
@@ -202,3 +209,6 @@
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/TimeStats/Android.bp b/services/surfaceflinger/TimeStats/Android.bp
index 20c2218..d27fbb4 100644
--- a/services/surfaceflinger/TimeStats/Android.bp
+++ b/services/surfaceflinger/TimeStats/Android.bp
@@ -8,12 +8,20 @@
"libcutils",
"liblog",
"libprotobuf-cpp-lite",
+ "libprotoutil",
+ "libstatslog",
+ "libstatspull",
+ "libstatssocket",
"libtimestats_proto",
"libui",
"libutils",
],
export_include_dirs: ["."],
export_shared_lib_headers: [
+ "libprotoutil",
+ "libstatslog",
+ "libstatspull",
+ "libstatssocket",
"libtimestats_proto",
],
cppflags: [
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index a5fabf2..12c98da 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -13,6 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
#undef LOG_TAG
#define LOG_TAG "TimeStats"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
@@ -20,6 +24,7 @@
#include "TimeStats.h"
#include <android-base/stringprintf.h>
+#include <android/util/ProtoOutputStream.h>
#include <log/log.h>
#include <utils/String8.h>
#include <utils/Timers.h>
@@ -32,11 +37,142 @@
namespace impl {
-TimeStats::TimeStats() {
+status_pull_atom_return_t TimeStats::pullAtomCallback(int32_t atom_tag,
+ pulled_stats_event_list* data, void* cookie) {
+ impl::TimeStats* timeStats = reinterpret_cast<impl::TimeStats*>(cookie);
+ if (atom_tag == android::util::SURFACEFLINGER_STATS_GLOBAL_INFO) {
+ return timeStats->populateGlobalAtom(data);
+ } else if (atom_tag == android::util::SURFACEFLINGER_STATS_LAYER_INFO) {
+ return timeStats->populateLayerAtom(data);
+ }
+
+ return STATS_PULL_SKIP;
+}
+
+status_pull_atom_return_t TimeStats::populateGlobalAtom(pulled_stats_event_list* data) {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ if (mTimeStats.statsStart == 0) {
+ return STATS_PULL_SKIP;
+ }
+ flushPowerTimeLocked();
+
+ struct stats_event* event = mStatsDelegate->addStatsEventToPullData(data);
+ mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_GLOBAL_INFO);
+ mStatsDelegate->statsEventWriteInt64(event, mTimeStats.totalFrames);
+ mStatsDelegate->statsEventWriteInt64(event, mTimeStats.missedFrames);
+ mStatsDelegate->statsEventWriteInt64(event, mTimeStats.clientCompositionFrames);
+ mStatsDelegate->statsEventWriteInt64(event, mTimeStats.displayOnTime);
+ mStatsDelegate->statsEventWriteInt64(event, mTimeStats.presentToPresent.totalTime());
+ mStatsDelegate->statsEventBuild(event);
+ clearGlobalLocked();
+
+ return STATS_PULL_SUCCESS;
+}
+
+namespace {
+// Histograms align with the order of fields in SurfaceflingerStatsLayerInfo.
+const std::array<std::string, 6> kHistogramNames = {
+ "present2present", "post2present", "acquire2present",
+ "latch2present", "desired2present", "post2acquire",
+};
+
+std::string histogramToProtoByteString(const std::unordered_map<int32_t, int32_t>& histogram,
+ size_t maxPulledHistogramBuckets) {
+ auto buckets = std::vector<std::pair<int32_t, int32_t>>(histogram.begin(), histogram.end());
+ std::sort(buckets.begin(), buckets.end(),
+ [](std::pair<int32_t, int32_t>& left, std::pair<int32_t, int32_t>& right) {
+ return left.second > right.second;
+ });
+
+ util::ProtoOutputStream proto;
+ int histogramSize = 0;
+ for (const auto& bucket : buckets) {
+ if (++histogramSize > maxPulledHistogramBuckets) {
+ break;
+ }
+ proto.write(android::util::FIELD_TYPE_INT32 | android::util::FIELD_COUNT_REPEATED |
+ 1 /* field id */,
+ (int32_t)bucket.first);
+ proto.write(android::util::FIELD_TYPE_INT64 | android::util::FIELD_COUNT_REPEATED |
+ 2 /* field id */,
+ (int64_t)bucket.second);
+ }
+
+ std::string byteString;
+ proto.serializeToString(&byteString);
+ return byteString;
+}
+} // namespace
+
+status_pull_atom_return_t TimeStats::populateLayerAtom(pulled_stats_event_list* data) {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ std::vector<TimeStatsHelper::TimeStatsLayer const*> dumpStats;
+ for (const auto& ele : mTimeStats.stats) {
+ dumpStats.push_back(&ele.second);
+ }
+
+ std::sort(dumpStats.begin(), dumpStats.end(),
+ [](TimeStatsHelper::TimeStatsLayer const* l,
+ TimeStatsHelper::TimeStatsLayer const* r) {
+ return l->totalFrames > r->totalFrames;
+ });
+
+ if (mMaxPulledLayers < dumpStats.size()) {
+ dumpStats.resize(mMaxPulledLayers);
+ }
+
+ for (const auto& layer : dumpStats) {
+ struct stats_event* event = mStatsDelegate->addStatsEventToPullData(data);
+ mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_LAYER_INFO);
+ mStatsDelegate->statsEventWriteString8(event, layer->layerName.c_str());
+ mStatsDelegate->statsEventWriteInt64(event, layer->totalFrames);
+ mStatsDelegate->statsEventWriteInt64(event, layer->droppedFrames);
+
+ for (const auto& name : kHistogramNames) {
+ const auto& histogram = layer->deltas.find(name);
+ if (histogram == layer->deltas.cend()) {
+ mStatsDelegate->statsEventWriteByteArray(event, nullptr, 0);
+ } else {
+ std::string bytes = histogramToProtoByteString(histogram->second.hist,
+ mMaxPulledHistogramBuckets);
+ mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)bytes.c_str(),
+ bytes.size());
+ }
+ }
+
+ mStatsDelegate->statsEventBuild(event);
+ }
+ clearLayersLocked();
+
+ return STATS_PULL_SUCCESS;
+}
+
+TimeStats::TimeStats() : TimeStats(nullptr, std::nullopt, std::nullopt) {}
+
+TimeStats::TimeStats(std::unique_ptr<StatsEventDelegate> statsDelegate,
+ std::optional<size_t> maxPulledLayers,
+ std::optional<size_t> maxPulledHistogramBuckets) {
+ if (statsDelegate != nullptr) {
+ mStatsDelegate = std::move(statsDelegate);
+ }
+
+ if (maxPulledLayers) {
+ mMaxPulledLayers = *maxPulledLayers;
+ }
+
+ if (maxPulledHistogramBuckets) {
+ mMaxPulledHistogramBuckets = *maxPulledHistogramBuckets;
+ }
+}
+
+void TimeStats::onBootFinished() {
// Temporarily enable TimeStats by default. Telemetry is disabled while
// we move onto statsd, so TimeStats is currently not exercised at all
- // during testing.
- // TODO: remove this.
+ // during testing without enabling by default.
+ // TODO: remove this, as we should only be paying this overhead on devices
+ // where statsd exists.
enable();
}
@@ -65,7 +201,7 @@
}
if (argsMap.count("-clear")) {
- clear();
+ clearAll();
}
if (argsMap.count("-enable")) {
@@ -112,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))
@@ -590,6 +735,10 @@
mEnabled.store(true);
mTimeStats.statsStart = static_cast<int64_t>(std::time(0));
mPowerTime.prevTime = systemTime();
+ mStatsDelegate->registerStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ TimeStats::pullAtomCallback, nullptr, this);
+ mStatsDelegate->registerStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
+ TimeStats::pullAtomCallback, nullptr, this);
ALOGD("Enabled");
}
@@ -602,20 +751,27 @@
flushPowerTimeLocked();
mEnabled.store(false);
mTimeStats.statsEnd = static_cast<int64_t>(std::time(0));
+ mStatsDelegate->unregisterStatsPullAtomCallback(
+ android::util::SURFACEFLINGER_STATS_GLOBAL_INFO);
+ mStatsDelegate->unregisterStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO);
ALOGD("Disabled");
}
-void TimeStats::clear() {
+void TimeStats::clearAll() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ clearGlobalLocked();
+ clearLayersLocked();
+}
+
+void TimeStats::clearGlobalLocked() {
ATRACE_CALL();
- std::lock_guard<std::mutex> lock(mMutex);
- mTimeStatsTracker.clear();
- mTimeStats.stats.clear();
mTimeStats.statsStart = (mEnabled.load() ? static_cast<int64_t>(std::time(0)) : 0);
mTimeStats.statsEnd = 0;
mTimeStats.totalFrames = 0;
mTimeStats.missedFrames = 0;
mTimeStats.clientCompositionFrames = 0;
+ mTimeStats.clientCompositionReusedFrames = 0;
mTimeStats.displayOnTime = 0;
mTimeStats.presentToPresent.hist.clear();
mTimeStats.frameDuration.hist.clear();
@@ -624,7 +780,15 @@
mPowerTime.prevTime = systemTime();
mGlobalRecord.prevPresentTime = 0;
mGlobalRecord.presentFences.clear();
- ALOGD("Cleared");
+ ALOGD("Cleared global stats");
+}
+
+void TimeStats::clearLayersLocked() {
+ ATRACE_CALL();
+
+ mTimeStatsTracker.clear();
+ mTimeStats.stats.clear();
+ ALOGD("Cleared layer stats");
}
bool TimeStats::isEnabled() {
@@ -657,3 +821,6 @@
} // namespace impl
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 65e5cf4..71f06af 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -17,6 +17,9 @@
#pragma once
#include <hardware/hwcomposer_defs.h>
+#include <stats_event.h>
+#include <stats_pull_atom_callback.h>
+#include <statslog.h>
#include <timestatsproto/TimeStatsHelper.h>
#include <timestatsproto/TimeStatsProtoHeader.h>
#include <ui/FenceTime.h>
@@ -37,6 +40,10 @@
public:
virtual ~TimeStats() = default;
+ // Called once boot has been finished to perform additional capabilities,
+ // e.g. registration to statsd.
+ virtual void onBootFinished() = 0;
+
virtual void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) = 0;
virtual bool isEnabled() = 0;
virtual std::string miniDump() = 0;
@@ -44,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
@@ -131,6 +139,50 @@
public:
TimeStats();
+ // Delegate to the statsd service and associated APIs.
+ // Production code may use this class directly, whereas unit test may define
+ // a subclass for ease of testing.
+ class StatsEventDelegate {
+ public:
+ virtual ~StatsEventDelegate() = default;
+ virtual struct stats_event* addStatsEventToPullData(pulled_stats_event_list* data) {
+ return add_stats_event_to_pull_data(data);
+ }
+ virtual void registerStatsPullAtomCallback(int32_t atom_tag,
+ stats_pull_atom_callback_t callback,
+ pull_atom_metadata* metadata, void* cookie) {
+ return register_stats_pull_atom_callback(atom_tag, callback, metadata, cookie);
+ }
+
+ virtual void unregisterStatsPullAtomCallback(int32_t atom_tag) {
+ return unregister_stats_pull_atom_callback(atom_tag);
+ }
+
+ virtual void statsEventSetAtomId(struct stats_event* event, uint32_t atom_id) {
+ return stats_event_set_atom_id(event, atom_id);
+ }
+
+ virtual void statsEventWriteInt64(struct stats_event* event, int64_t field) {
+ return stats_event_write_int64(event, field);
+ }
+
+ virtual void statsEventWriteString8(struct stats_event* event, const char* field) {
+ return stats_event_write_string8(event, field);
+ }
+
+ virtual void statsEventWriteByteArray(struct stats_event* event, const uint8_t* buf,
+ size_t numBytes) {
+ return stats_event_write_byte_array(event, buf, numBytes);
+ }
+
+ virtual void statsEventBuild(struct stats_event* event) { return stats_event_build(event); }
+ };
+ // For testing only for injecting custom dependencies.
+ TimeStats(std::unique_ptr<StatsEventDelegate> statsDelegate,
+ std::optional<size_t> maxPulledLayers,
+ std::optional<size_t> maxPulledHistogramBuckets);
+
+ void onBootFinished() override;
void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) override;
bool isEnabled() override;
std::string miniDump() override;
@@ -138,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;
@@ -167,6 +220,10 @@
static const size_t MAX_NUM_TIME_RECORDS = 64;
private:
+ static status_pull_atom_return_t pullAtomCallback(int32_t atom_tag,
+ pulled_stats_event_list* data, void* cookie);
+ status_pull_atom_return_t populateGlobalAtom(pulled_stats_event_list* data);
+ status_pull_atom_return_t populateLayerAtom(pulled_stats_event_list* data);
bool recordReadyLocked(int32_t layerId, TimeRecord* timeRecord);
void flushAvailableRecordsToStatsLocked(int32_t layerId);
void flushPowerTimeLocked();
@@ -174,7 +231,9 @@
void enable();
void disable();
- void clear();
+ void clearAll();
+ void clearGlobalLocked();
+ void clearLayersLocked();
void dump(bool asProto, std::optional<uint32_t> maxLayers, std::string& result);
std::atomic<bool> mEnabled = false;
@@ -187,6 +246,9 @@
static const size_t MAX_NUM_LAYER_RECORDS = 200;
static const size_t MAX_NUM_LAYER_STATS = 200;
+ std::unique_ptr<StatsEventDelegate> mStatsDelegate = std::make_unique<StatsEventDelegate>();
+ size_t mMaxPulledLayers = 8;
+ size_t mMaxPulledHistogramBuckets = 6;
};
} // namespace impl
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/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
index 1475889..daa67ae 100644
--- a/services/surfaceflinger/TransactionCompletedThread.cpp
+++ b/services/surfaceflinger/TransactionCompletedThread.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
//#define LOG_NDEBUG 0
#undef LOG_TAG
#define LOG_TAG "TransactionCompletedThread"
@@ -355,3 +359,6 @@
: listener(transactionListener), callbackIds(ids), surfaceControl(sc) {}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
index ef27847..8fce0c9 100644
--- a/services/surfaceflinger/layerproto/LayerProtoParser.cpp
+++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
@@ -106,6 +106,7 @@
layer.refreshPending = layerProto.refresh_pending();
layer.isProtected = layerProto.is_protected();
layer.cornerRadius = layerProto.corner_radius();
+ layer.backgroundBlurRadius = layerProto.background_blur_radius();
for (const auto& entry : layerProto.metadata()) {
const std::string& dataStr = entry.second;
std::vector<uint8_t>& outData = layer.metadata.mMap[entry.first];
@@ -290,6 +291,7 @@
StringAppendF(&result, "isOpaque=%1d, invalidate=%1d, ", isOpaque, invalidate);
StringAppendF(&result, "dataspace=%s, ", dataspace.c_str());
StringAppendF(&result, "defaultPixelFormat=%s, ", pixelFormat.c_str());
+ StringAppendF(&result, "backgroundBlurRadius=%1d, ", backgroundBlurRadius);
StringAppendF(&result, "color=(%.3f,%.3f,%.3f,%.3f), flags=0x%08x, ",
static_cast<double>(color.r), static_cast<double>(color.g),
static_cast<double>(color.b), static_cast<double>(color.a), flags);
diff --git a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
index 774b0e1..52b9165 100644
--- a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
+++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
@@ -110,6 +110,7 @@
bool refreshPending;
bool isProtected;
float cornerRadius;
+ int backgroundBlurRadius;
LayerMetadata metadata;
LayerProtoParser::FloatRect cornerRadiusCrop;
float shadowRadius;
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index 41ecafa..8afe503 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -104,6 +104,8 @@
ColorTransformProto color_transform = 50;
bool is_relative_of = 51;
+ // Layer's background blur radius in pixels.
+ int32 background_blur_radius = 52;
}
message PositionProto {
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index e7986d3..d7ad9de 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <sys/resource.h>
#include <sched.h>
@@ -121,3 +125,6 @@
return 0;
}
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index 049c872..ed2b220 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -371,3 +371,12 @@
access: Readonly
prop_name: "ro.surface_flinger.support_kernel_idle_timer"
}
+
+# Indicates whether background blurs are supported.
+prop {
+ api_name: "supports_background_blur"
+ type: Boolean
+ scope: Public
+ access: Readonly
+ prop_name: "ro.surface_flinger.supports_background_blur"
+}
diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
index 2d52507..d24ad18 100644
--- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
+++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
@@ -104,6 +104,10 @@
prop_name: "ro.surface_flinger.support_kernel_idle_timer"
}
prop {
+ api_name: "supports_background_blur"
+ prop_name: "ro.surface_flinger.supports_background_blur"
+ }
+ prop {
api_name: "use_color_management"
prop_name: "ro.surface_flinger.use_color_management"
}
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index 1c8199a..94ebe89 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -32,6 +32,7 @@
"MirrorLayer_test.cpp",
"MultiDisplayLayerBounds_test.cpp",
"RelativeZ_test.cpp",
+ "SetFrameRate_test.cpp",
"SetGeometry_test.cpp",
"Stress_test.cpp",
"SurfaceInterceptor_test.cpp",
diff --git a/services/surfaceflinger/tests/BufferGenerator.cpp b/services/surfaceflinger/tests/BufferGenerator.cpp
index 8ddda60..293738c 100644
--- a/services/surfaceflinger/tests/BufferGenerator.cpp
+++ b/services/surfaceflinger/tests/BufferGenerator.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <gui/BufferItemConsumer.h>
#include <gui/Surface.h>
@@ -379,3 +383,6 @@
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index f618873..f339ab0 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -31,6 +31,10 @@
* Methods like EnableVsyncInjections and InjectVsync are not tested since they do not
* return anything meaningful.
*/
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
class CredentialsTest : public ::testing::Test {
protected:
void SetUp() override {
@@ -214,10 +218,17 @@
ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, NO_ERROR));
}
-TEST_F(CredentialsTest, SetActiveConfigTest) {
+TEST_F(CredentialsTest, SetDesiredDisplayConfigsTest) {
const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ int32_t defaultConfig;
+ float minFps;
+ float maxFps;
+ status_t res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(display, &defaultConfig,
+ &minFps, &maxFps);
+ ASSERT_EQ(res, NO_ERROR);
std::function<status_t()> condition = [=]() {
- return SurfaceComposerClient::setActiveConfig(display, 0);
+ return SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, defaultConfig, minFps,
+ maxFps);
};
ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
}
@@ -362,3 +373,6 @@
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/DereferenceSurfaceControl_test.cpp b/services/surfaceflinger/tests/DereferenceSurfaceControl_test.cpp
index 0cef0d1..46b98f9 100644
--- a/services/surfaceflinger/tests/DereferenceSurfaceControl_test.cpp
+++ b/services/surfaceflinger/tests/DereferenceSurfaceControl_test.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include "LayerTransactionTest.h"
namespace android {
@@ -67,3 +71,6 @@
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/DisplayConfigs_test.cpp b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
index d51b9a1..3aa4474 100644
--- a/services/surfaceflinger/tests/DisplayConfigs_test.cpp
+++ b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <thread>
#include "LayerTransactionTest.h"
namespace android {
@@ -68,3 +72,6 @@
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp
index 7a5ed48..6d28e62 100644
--- a/services/surfaceflinger/tests/LayerCallback_test.cpp
+++ b/services/surfaceflinger/tests/LayerCallback_test.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include "LayerTransactionTest.h"
#include "utils/CallbackUtils.h"
@@ -870,3 +874,6 @@
EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
index 92698f0..24874b0 100644
--- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <gui/BufferItemConsumer.h>
#include <ui/Transform.h>
#include <thread>
@@ -1841,3 +1845,6 @@
}
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/LayerTransaction_test.cpp b/services/surfaceflinger/tests/LayerTransaction_test.cpp
index 7816c66..97cba63 100644
--- a/services/surfaceflinger/tests/LayerTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTransaction_test.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <private/android_filesystem_config.h>
#include <thread>
#include "LayerTransactionTest.h"
@@ -190,3 +194,6 @@
ASSERT_EQ(OK, producer->disconnect(NATIVE_WINDOW_API_CPU));
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
index daeff17..3bbd12a 100644
--- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
@@ -14,6 +14,11 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include <cutils/properties.h>
#include <gui/BufferItemConsumer.h>
#include "TransactionTestHarnesses.h"
@@ -239,6 +244,41 @@
shot->expectColor(Rect(right - testArea, bottom - testArea, right, bottom), Color::BLACK);
}
}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadius) {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.surface_flinger.supports_background_blur", value, "0");
+ if (!atoi(value)) {
+ // This device doesn't support blurs, no-op.
+ return;
+ }
+
+ auto size = 256;
+ auto center = size / 2;
+ auto blurRadius = 50;
+
+ sp<SurfaceControl> backgroundLayer;
+ ASSERT_NO_FATAL_FAILURE(backgroundLayer = createLayer("background", size, size));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(backgroundLayer, Color::GREEN, size, size));
+
+ sp<SurfaceControl> leftLayer;
+ ASSERT_NO_FATAL_FAILURE(leftLayer = createLayer("left", size / 2, size));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(leftLayer, Color::RED, size / 2, size));
+
+ sp<SurfaceControl> blurLayer;
+ ASSERT_NO_FATAL_FAILURE(blurLayer = createLayer("blur", size, size));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(blurLayer, Color::TRANSPARENT, size, size));
+
+ Transaction().setBackgroundBlurRadius(blurLayer, blurRadius).apply();
+
+ auto shot = getScreenCapture();
+ // Edges are mixed
+ shot->expectColor(Rect(center - 1, center - 5, center, center + 5), Color{150, 150, 0, 255},
+ 50 /* tolerance */);
+ shot->expectColor(Rect(center, center - 5, center + 1, center + 5), Color{150, 150, 0, 255},
+ 50 /* tolerance */);
+}
+
TEST_P(LayerTypeAndRenderTypeTransactionTest, SetColorWithBuffer) {
sp<SurfaceControl> bufferLayer;
ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test", 32, 32));
@@ -267,3 +307,6 @@
}
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
index 42ec34a..7e9202b 100644
--- a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <gui/BufferItemConsumer.h>
#include "TransactionTestHarnesses.h"
@@ -186,3 +190,6 @@
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp
index 0ad122b..0459386 100644
--- a/services/surfaceflinger/tests/LayerUpdate_test.cpp
+++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include "LayerTransactionTest.h"
namespace android {
@@ -1708,3 +1712,6 @@
ASSERT_EQ(NAME_NOT_FOUND, sf->captureLayers(redLayerHandle, &outBuffer, Rect::EMPTY_RECT, 1.0));
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/MirrorLayer_test.cpp b/services/surfaceflinger/tests/MirrorLayer_test.cpp
index 0bcac1a..b49bd54 100644
--- a/services/surfaceflinger/tests/MirrorLayer_test.cpp
+++ b/services/surfaceflinger/tests/MirrorLayer_test.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include "LayerTransactionTest.h"
namespace android {
@@ -224,3 +228,6 @@
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
index 066c9aa..e525e2a 100644
--- a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
+++ b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include "LayerTransactionTest.h"
namespace android {
@@ -122,3 +126,6 @@
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/RelativeZ_test.cpp b/services/surfaceflinger/tests/RelativeZ_test.cpp
index 8c56d27..1180cac 100644
--- a/services/surfaceflinger/tests/RelativeZ_test.cpp
+++ b/services/surfaceflinger/tests/RelativeZ_test.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include "LayerTransactionTest.h"
namespace android {
@@ -204,3 +208,6 @@
}
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/SetFrameRate_test.cpp b/services/surfaceflinger/tests/SetFrameRate_test.cpp
new file mode 100644
index 0000000..fc65263
--- /dev/null
+++ b/services/surfaceflinger/tests/SetFrameRate_test.cpp
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include <system/window.h>
+
+#include <thread>
+
+#include "LayerTransactionTest.h"
+
+namespace android {
+
+class SetFrameRateTest : public LayerTransactionTest {
+protected:
+ void TearDown() {
+ mLayer = nullptr;
+ LayerTransactionTest::TearDown();
+ }
+
+ void CreateLayer(uint32_t layerType) {
+ ASSERT_EQ(nullptr, mLayer.get());
+ mLayerType = layerType;
+ ASSERT_NO_FATAL_FAILURE(mLayer = createLayer("TestLayer", mLayerWidth, mLayerHeight,
+ /*flags=*/mLayerType));
+ ASSERT_NE(nullptr, mLayer.get());
+ }
+
+ void PostBuffers(const Color& color) {
+ auto startTime = systemTime();
+ while (systemTime() - startTime < s2ns(1)) {
+ ASSERT_NO_FATAL_FAILURE(
+ fillLayerColor(mLayerType, mLayer, color, mLayerWidth, mLayerHeight));
+ std::this_thread::sleep_for(100ms);
+ }
+ }
+
+ const int mLayerWidth = 32;
+ const int mLayerHeight = 32;
+ sp<SurfaceControl> mLayer;
+ uint32_t mLayerType;
+};
+
+TEST_F(SetFrameRateTest, BufferQueueLayerSetFrameRate) {
+ CreateLayer(ISurfaceComposerClient::eFXSurfaceBufferQueue);
+ native_window_set_frame_rate(mLayer->getSurface().get(), 100.f);
+ ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::RED));
+ Transaction().setFrameRate(mLayer, 200.f).apply();
+ ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::RED));
+ native_window_set_frame_rate(mLayer->getSurface().get(), 300.f);
+ ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::RED));
+}
+
+TEST_F(SetFrameRateTest, BufferStateLayerSetFrameRate) {
+ CreateLayer(ISurfaceComposerClient::eFXSurfaceBufferState);
+ Transaction().setFrameRate(mLayer, 400.f).apply();
+ ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::GREEN));
+}
+
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/SetGeometry_test.cpp b/services/surfaceflinger/tests/SetGeometry_test.cpp
index dca06ec..5fe2513 100644
--- a/services/surfaceflinger/tests/SetGeometry_test.cpp
+++ b/services/surfaceflinger/tests/SetGeometry_test.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include "LayerTransactionTest.h"
namespace android {
@@ -97,3 +101,6 @@
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/Stress_test.cpp b/services/surfaceflinger/tests/Stress_test.cpp
index ee857b0..e9b6ba0 100644
--- a/services/surfaceflinger/tests/Stress_test.cpp
+++ b/services/surfaceflinger/tests/Stress_test.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <gtest/gtest.h>
#include <gui/SurfaceComposerClient.h>
@@ -107,3 +111,6 @@
}
}
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 1fa426d..4a2ab7c 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <frameworks/native/cmds/surfacereplayer/proto/src/trace.pb.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
@@ -49,6 +53,7 @@
constexpr int32_t RELATIVE_Z = 42;
constexpr float ALPHA_UPDATE = 0.29f;
constexpr float CORNER_RADIUS_UPDATE = 0.2f;
+constexpr int BACKGROUND_BLUR_RADIUS_UPDATE = 24;
constexpr float POSITION_UPDATE = 121;
const Rect CROP_UPDATE(16, 16, 32, 32);
const float SHADOW_RADIUS_UPDATE = 35.0f;
@@ -179,6 +184,8 @@
bool layerUpdateFound(const SurfaceChange& change, bool foundLayer);
bool cropUpdateFound(const SurfaceChange& change, bool foundCrop);
bool cornerRadiusUpdateFound(const SurfaceChange& change, bool foundCornerRadius);
+ bool backgroundBlurRadiusUpdateFound(const SurfaceChange& change,
+ bool foundBackgroundBlurRadius);
bool matrixUpdateFound(const SurfaceChange& change, bool foundMatrix);
bool scalingModeUpdateFound(const SurfaceChange& change, bool foundScalingMode);
bool transparentRegionHintUpdateFound(const SurfaceChange& change, bool foundTransparentRegion);
@@ -216,6 +223,7 @@
void layerUpdate(Transaction&);
void cropUpdate(Transaction&);
void cornerRadiusUpdate(Transaction&);
+ void backgroundBlurRadiusUpdate(Transaction&);
void matrixUpdate(Transaction&);
void overrideScalingModeUpdate(Transaction&);
void transparentRegionHintUpdate(Transaction&);
@@ -351,6 +359,10 @@
t.setCornerRadius(mBGSurfaceControl, CORNER_RADIUS_UPDATE);
}
+void SurfaceInterceptorTest::backgroundBlurRadiusUpdate(Transaction& t) {
+ t.setBackgroundBlurRadius(mBGSurfaceControl, BACKGROUND_BLUR_RADIUS_UPDATE);
+}
+
void SurfaceInterceptorTest::layerUpdate(Transaction& t) {
t.setLayer(mBGSurfaceControl, LAYER_UPDATE);
}
@@ -428,6 +440,7 @@
runInTransaction(&SurfaceInterceptorTest::sizeUpdate);
runInTransaction(&SurfaceInterceptorTest::alphaUpdate);
runInTransaction(&SurfaceInterceptorTest::cornerRadiusUpdate);
+ runInTransaction(&SurfaceInterceptorTest::backgroundBlurRadiusUpdate);
runInTransaction(&SurfaceInterceptorTest::layerUpdate);
runInTransaction(&SurfaceInterceptorTest::cropUpdate);
runInTransaction(&SurfaceInterceptorTest::matrixUpdate);
@@ -505,6 +518,18 @@
return foundCornerRadius;
}
+bool SurfaceInterceptorTest::backgroundBlurRadiusUpdateFound(const SurfaceChange& change,
+ bool foundBackgroundBlur) {
+ bool hasBackgroundBlur(change.background_blur_radius().background_blur_radius() ==
+ BACKGROUND_BLUR_RADIUS_UPDATE);
+ if (hasBackgroundBlur && !foundBackgroundBlur) {
+ foundBackgroundBlur = true;
+ } else if (hasBackgroundBlur && foundBackgroundBlur) {
+ []() { FAIL(); }();
+ }
+ return foundBackgroundBlur;
+}
+
bool SurfaceInterceptorTest::layerUpdateFound(const SurfaceChange& change, bool foundLayer) {
bool hasLayer(change.layer().layer() == LAYER_UPDATE);
if (hasLayer && !foundLayer) {
@@ -701,6 +726,9 @@
case SurfaceChange::SurfaceChangeCase::kCornerRadius:
foundUpdate = cornerRadiusUpdateFound(change, foundUpdate);
break;
+ case SurfaceChange::SurfaceChangeCase::kBackgroundBlurRadius:
+ foundUpdate = backgroundBlurRadiusUpdateFound(change, foundUpdate);
+ break;
case SurfaceChange::SurfaceChangeCase::kMatrix:
foundUpdate = matrixUpdateFound(change, foundUpdate);
break;
@@ -883,6 +911,11 @@
SurfaceChange::SurfaceChangeCase::kCornerRadius);
}
+TEST_F(SurfaceInterceptorTest, InterceptBackgroundBlurRadiusUpdateWorks) {
+ captureTest(&SurfaceInterceptorTest::backgroundBlurRadiusUpdate,
+ SurfaceChange::SurfaceChangeCase::kBackgroundBlurRadius);
+}
+
TEST_F(SurfaceInterceptorTest, InterceptMatrixUpdateWorks) {
captureTest(&SurfaceInterceptorTest::matrixUpdate, SurfaceChange::SurfaceChangeCase::kMatrix);
}
@@ -1011,3 +1044,6 @@
ASSERT_TRUE(singleIncrementFound(capturedTrace, Increment::IncrementCase::kSurfaceCreation));
}
}
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
index 0c370a6..5cbf2ef 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
//#define LOG_NDEBUG 0
#undef LOG_TAG
#define LOG_TAG "FakeComposer"
@@ -776,6 +780,27 @@
return V2_4::Error::UNSUPPORTED;
}
+V2_4::Error FakeComposerClient::validateDisplay_2_4(
+ Display /*display*/, std::vector<Layer>* /*outChangedLayers*/,
+ std::vector<IComposerClient::Composition>* /*outCompositionTypes*/,
+ uint32_t* /*outDisplayRequestMask*/, std::vector<Layer>* /*outRequestedLayers*/,
+ std::vector<uint32_t>* /*outRequestMasks*/,
+ IComposerClient::ClientTargetProperty* /*outClientTargetProperty*/) {
+ return V2_4::Error::NONE;
+}
+
+V2_4::Error FakeComposerClient::setLayerGenericMetadata(Display, Layer, const std::string&, bool,
+ const std::vector<uint8_t>&) {
+ ALOGV("setLayerGenericMetadata");
+ return V2_4::Error::UNSUPPORTED;
+}
+
+V2_4::Error FakeComposerClient::getLayerGenericMetadataKeys(
+ std::vector<IComposerClient::LayerGenericMetadataKey>*) {
+ ALOGV("getLayerGenericMetadataKeys");
+ return V2_4::Error::UNSUPPORTED;
+}
+
//////////////////////////////////////////////////////////////////
void FakeComposerClient::requestVSync(uint64_t vsyncTime) {
@@ -896,3 +921,6 @@
// this might get more involving.
return static_cast<Layer>(index);
}
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
index f9ff2bf..5240b72 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
@@ -251,6 +251,16 @@
Display display,
std::vector<IComposerClient::ContentType>* outSupportedContentTypes) override;
V2_4::Error setContentType(Display display, IComposerClient::ContentType type) override;
+ V2_4::Error validateDisplay_2_4(
+ Display display, std::vector<Layer>* outChangedLayers,
+ std::vector<IComposerClient::Composition>* outCompositionTypes,
+ uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers,
+ std::vector<uint32_t>* outRequestMasks,
+ IComposerClient::ClientTargetProperty* outClientTargetProperty) override;
+ V2_4::Error setLayerGenericMetadata(Display display, Layer layer, const std::string& key,
+ bool mandatory, const std::vector<uint8_t>& value) override;
+ V2_4::Error getLayerGenericMetadataKeys(
+ std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) override;
void setClient(ComposerClient* client);
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp
index f727bc4..c656eed 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#define LOG_NDEBUG 0
#undef LOG_TAG
#define LOG_TAG "FakeHwcService"
@@ -170,3 +174,6 @@
}
} // namespace sftest
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp
index 4d21468..2f89696 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#define LOG_NDEBUG 0
#undef LOG_TAG
#define LOG_TAG "FakeHwcUtil"
@@ -183,3 +187,6 @@
}
} // namespace sftest
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 09fdbdf..6874f6f 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
// #define LOG_NDEBUG 0
#undef LOG_TAG
#define LOG_TAG "FakeHwcTest"
@@ -433,7 +437,10 @@
for (int i = 0; i < configs.size(); i++) {
if (configs[i].w == 800u) {
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::setActiveConfig(display, i));
+ EXPECT_EQ(NO_ERROR,
+ SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
+ configs[i].fps,
+ configs[i].fps));
waitForDisplayTransaction();
EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
break;
@@ -531,7 +538,10 @@
for (int i = 0; i < configs.size(); i++) {
if (configs[i].fps == 1e9f / 11'111'111) {
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::setActiveConfig(display, i));
+ EXPECT_EQ(NO_ERROR,
+ SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
+ configs[i].fps,
+ configs[i].fps));
waitForDisplayTransaction();
EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
break;
@@ -639,7 +649,10 @@
for (int i = 0; i < configs.size(); i++) {
if (configs[i].w == 800u && configs[i].fps == 1e9f / 11'111'111) {
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::setActiveConfig(display, i));
+ EXPECT_EQ(NO_ERROR,
+ SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
+ configs[i].fps,
+ configs[i].fps));
waitForDisplayTransaction();
EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
break;
@@ -679,7 +692,10 @@
for (int i = 0; i < configs.size(); i++) {
if (configs[i].fps == 1e9f / 8'333'333) {
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::setActiveConfig(display, i));
+ EXPECT_EQ(NO_ERROR,
+ SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
+ configs[i].fps,
+ configs[i].fps));
waitForDisplayTransaction();
EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
break;
@@ -719,7 +735,10 @@
for (int i = 0; i < configs.size(); i++) {
if (configs[i].w == 1600 && configs[i].fps == 1e9f / 11'111'111) {
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::setActiveConfig(display, i));
+ EXPECT_EQ(NO_ERROR,
+ SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
+ configs[i].fps,
+ configs[i].fps));
waitForDisplayTransaction();
EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
break;
@@ -1970,3 +1989,6 @@
::testing::InitGoogleMock(&argc, argv);
return RUN_ALL_TESTS();
}
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp b/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp
index 13774b4..f9a1fe9 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <array>
#include <unordered_set>
#include <unordered_map>
@@ -4770,3 +4774,6 @@
ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage,
virtualDisplayExceptions));
}
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp
index 6484562..fcd0d31 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <mutex>
#include <array>
#include <sstream>
@@ -789,3 +793,6 @@
return 0;
}
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp
index 90127a1..b76ace8 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp
@@ -13,6 +13,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <sstream>
#include <gtest/gtest.h>
@@ -279,3 +283,6 @@
return optimized;
}
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.cpp
index 904b927..8ca8815 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <sstream>
#include <android/hardware/graphics/common/1.0/types.h>
@@ -111,3 +115,6 @@
}
return stream.str();
}
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp
index c5b92d0..1efb21e 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <sstream>
#include <cutils/log.h>
#include <ui/Rect.h>
@@ -780,3 +784,6 @@
const std::array<bool, 6> Hwc2TestTransform::mCompositionSupport = {{
false, true, true, false, true, true,
}};
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index e4ef19e..d046f76 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -44,11 +44,13 @@
"EventThreadTest.cpp",
"OneShotTimerTest.cpp",
"LayerHistoryTest.cpp",
+ "LayerHistoryTestV2.cpp",
"LayerMetadataTest.cpp",
"PhaseOffsetsTest.cpp",
"SchedulerTest.cpp",
"SchedulerUtilsTest.cpp",
"RefreshRateConfigsTest.cpp",
+ "RefreshRateSelectionTest.cpp",
"RefreshRateStatsTest.cpp",
"RegionSamplingTest.cpp",
"TimeStatsTest.cpp",
@@ -82,6 +84,8 @@
"perfetto_trace_protos",
],
shared_libs: [
+ "libprotoutil",
+ "libstatssocket",
"libsurfaceflinger",
"libtimestats",
"libtimestats_proto",
diff --git a/services/surfaceflinger/tests/unittests/CachingTest.cpp b/services/surfaceflinger/tests/unittests/CachingTest.cpp
index 74ce540..1b8c76d 100644
--- a/services/surfaceflinger/tests/unittests/CachingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CachingTest.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#undef LOG_TAG
#define LOG_TAG "CachingTest"
@@ -91,3 +95,6 @@
}
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index cce21ce..98cc023 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#undef LOG_TAG
#define LOG_TAG "CompositionTest"
@@ -324,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);
@@ -373,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);
@@ -623,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);
@@ -639,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;
});
}
@@ -672,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);
@@ -688,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;
});
}
@@ -748,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);
@@ -764,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;
});
}
@@ -1423,3 +1429,6 @@
} // namespace
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 55c3ab8..9680a17 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"
@@ -21,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>
@@ -1274,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
*/
@@ -3239,3 +3481,6 @@
} // namespace
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp
index c334bcf..68cb52f 100644
--- a/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"
@@ -394,3 +398,6 @@
} // namespace
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index f055fe7..9ca1b70 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -1,3 +1,23 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#undef LOG_TAG
#define LOG_TAG "LayerHistoryTest"
@@ -53,7 +73,7 @@
HI_FPS_PERIOD},
},
HwcConfigIndexType(0)};
- TestableScheduler* const mScheduler{new TestableScheduler(mConfigs)};
+ TestableScheduler* const mScheduler{new TestableScheduler(mConfigs, false)};
TestableSurfaceFlinger mFlinger;
const nsecs_t mTime = systemTime();
@@ -64,51 +84,37 @@
TEST_F(LayerHistoryTest, oneLayer) {
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameSelectionPriority()).WillRepeatedly(Return(1));
+ EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(std::nullopt));
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
- // 0 FPS is returned if no layers are active.
- EXPECT_FLOAT_EQ(0, history().summarize(mTime).maxRefreshRate);
+ // no layers are returned if no layers are active.
+ ASSERT_TRUE(history().summarize(mTime).empty());
EXPECT_EQ(0, activeLayerCount());
- // 0 FPS is returned if active layers have insufficient history.
+ // no layers are returned if active layers have insufficient history.
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) {
history().record(layer.get(), 0, mTime);
- EXPECT_FLOAT_EQ(0, history().summarize(mTime).maxRefreshRate);
+ ASSERT_TRUE(history().summarize(mTime).empty());
EXPECT_EQ(1, activeLayerCount());
}
// High FPS is returned once enough history has been recorded.
for (int i = 0; i < 10; i++) {
history().record(layer.get(), 0, mTime);
- EXPECT_FLOAT_EQ(HI_FPS, history().summarize(mTime).maxRefreshRate);
+ ASSERT_EQ(1, history().summarize(mTime).size());
+ EXPECT_FLOAT_EQ(HI_FPS, history().summarize(mTime)[0].desiredRefreshRate);
EXPECT_EQ(1, activeLayerCount());
}
}
-TEST_F(LayerHistoryTest, oneHDRLayer) {
- const auto layer = createLayer();
- EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
-
- EXPECT_EQ(1, layerCount());
- EXPECT_EQ(0, activeLayerCount());
-
- history().record(layer.get(), 0, mTime);
- auto summary = history().summarize(mTime);
- EXPECT_FLOAT_EQ(0, summary.maxRefreshRate);
- EXPECT_EQ(1, activeLayerCount());
-
- EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(false));
-
- summary = history().summarize(mTime);
- EXPECT_FLOAT_EQ(0, summary.maxRefreshRate);
- EXPECT_EQ(0, activeLayerCount());
-}
-
TEST_F(LayerHistoryTest, explicitTimestamp) {
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameSelectionPriority()).WillRepeatedly(Return(1));
+ EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(std::nullopt));
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
@@ -119,7 +125,8 @@
time += LO_FPS_PERIOD;
}
- EXPECT_FLOAT_EQ(LO_FPS, history().summarize(mTime).maxRefreshRate);
+ ASSERT_EQ(1, history().summarize(mTime).size());
+ EXPECT_FLOAT_EQ(LO_FPS, history().summarize(mTime)[0].desiredRefreshRate);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
}
@@ -130,9 +137,16 @@
auto layer3 = createLayer();
EXPECT_CALL(*layer1, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer2, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer3, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer1, getFrameSelectionPriority()).WillRepeatedly(Return(1));
+ EXPECT_CALL(*layer1, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer2, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer2, getFrameSelectionPriority()).WillRepeatedly(Return(1));
+ EXPECT_CALL(*layer2, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+
+ EXPECT_CALL(*layer3, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer3, getFrameSelectionPriority()).WillRepeatedly(Return(1));
+ EXPECT_CALL(*layer3, getFrameRate()).WillRepeatedly(Return(std::nullopt));
nsecs_t time = mTime;
EXPECT_EQ(3, layerCount());
@@ -145,7 +159,8 @@
time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
}
- EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time).maxRefreshRate);
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
@@ -158,7 +173,9 @@
// layer1 is still active but infrequent.
history().record(layer1.get(), time, time);
- EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time).maxRefreshRate);
+ ASSERT_EQ(2, history().summarize(time).size());
+ EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time)[1].desiredRefreshRate);
EXPECT_EQ(2, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
@@ -169,7 +186,8 @@
time += LO_FPS_PERIOD;
}
- EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time).maxRefreshRate);
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
@@ -185,19 +203,24 @@
time += HI_FPS_PERIOD;
}
- EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time).maxRefreshRate);
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
EXPECT_EQ(2, activeLayerCount());
EXPECT_EQ(2, frequentLayerCount(time));
// layer3 becomes recently active.
history().record(layer3.get(), time, time);
- EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time).maxRefreshRate);
+ ASSERT_EQ(2, history().summarize(time).size());
+ EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time)[1].desiredRefreshRate);
EXPECT_EQ(2, activeLayerCount());
EXPECT_EQ(2, frequentLayerCount(time));
// layer1 expires.
layer1.clear();
- EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time).maxRefreshRate);
+ ASSERT_EQ(2, history().summarize(time).size());
+ EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time)[1].desiredRefreshRate);
EXPECT_EQ(2, layerCount());
EXPECT_EQ(2, activeLayerCount());
EXPECT_EQ(2, frequentLayerCount(time));
@@ -209,13 +232,14 @@
time += LO_FPS_PERIOD;
}
- EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time).maxRefreshRate);
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
// layer2 expires.
layer2.clear();
- EXPECT_FLOAT_EQ(0, history().summarize(time).maxRefreshRate);
+ ASSERT_TRUE(history().summarize(time).empty());
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
@@ -226,14 +250,15 @@
time += HI_FPS_PERIOD;
}
- EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time).maxRefreshRate);
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time)[0].desiredRefreshRate);
EXPECT_EQ(1, layerCount());
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
// layer3 expires.
layer3.clear();
- EXPECT_FLOAT_EQ(0, history().summarize(time).maxRefreshRate);
+ ASSERT_TRUE(history().summarize(time).empty());
EXPECT_EQ(0, layerCount());
EXPECT_EQ(0, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
@@ -241,3 +266,6 @@
} // namespace
} // namespace android::scheduler
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
new file mode 100644
index 0000000..11ace05
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
@@ -0,0 +1,418 @@
+/*
+ * 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LayerHistoryTestV2"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+
+#include "Scheduler/LayerHistory.h"
+#include "Scheduler/LayerInfoV2.h"
+#include "TestableScheduler.h"
+#include "TestableSurfaceFlinger.h"
+#include "mock/MockLayer.h"
+
+using testing::_;
+using testing::Return;
+
+namespace android::scheduler {
+
+class LayerHistoryTestV2 : public testing::Test {
+protected:
+ static constexpr auto PRESENT_TIME_HISTORY_SIZE = LayerInfoV2::HISTORY_SIZE;
+ static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS = LayerInfoV2::MAX_FREQUENT_LAYER_PERIOD_NS;
+
+ static constexpr float LO_FPS = 30.f;
+ static constexpr auto LO_FPS_PERIOD = static_cast<nsecs_t>(1e9f / LO_FPS);
+
+ static constexpr float HI_FPS = 90.f;
+ static constexpr auto HI_FPS_PERIOD = static_cast<nsecs_t>(1e9f / HI_FPS);
+
+ LayerHistoryTestV2() { mFlinger.resetScheduler(mScheduler); }
+
+ impl::LayerHistoryV2& history() { return *mScheduler->mutableLayerHistoryV2(); }
+ const impl::LayerHistoryV2& history() const { return *mScheduler->mutableLayerHistoryV2(); }
+
+ size_t layerCount() const { return mScheduler->layerHistorySize(); }
+ size_t activeLayerCount() const NO_THREAD_SAFETY_ANALYSIS { return history().mActiveLayersEnd; }
+
+ auto frequentLayerCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS {
+ const auto& infos = history().mLayerInfos;
+ return std::count_if(infos.begin(),
+ infos.begin() + static_cast<long>(history().mActiveLayersEnd),
+ [now](const auto& pair) { return pair.second->isFrequent(now); });
+ }
+
+ void setLayerInfoVote(Layer* layer,
+ LayerHistory::LayerVoteType vote) NO_THREAD_SAFETY_ANALYSIS {
+ for (auto& [weak, info] : history().mLayerInfos) {
+ if (auto strong = weak.promote(); strong && strong.get() == layer) {
+ info->setDefaultLayerVote(vote);
+ info->setLayerVote(vote, 0);
+ return;
+ }
+ }
+ }
+
+ auto createLayer() { return sp<mock::MockLayer>(new mock::MockLayer(mFlinger.flinger())); }
+
+ RefreshRateConfigs mConfigs{true,
+ {
+ RefreshRateConfigs::InputConfig{HwcConfigIndexType(0),
+ HwcConfigGroupType(0),
+ LO_FPS_PERIOD},
+ RefreshRateConfigs::InputConfig{HwcConfigIndexType(1),
+ HwcConfigGroupType(0),
+ HI_FPS_PERIOD},
+ },
+ HwcConfigIndexType(0)};
+ TestableScheduler* const mScheduler{new TestableScheduler(mConfigs, true)};
+ TestableSurfaceFlinger mFlinger;
+
+ const nsecs_t mTime = systemTime();
+};
+
+namespace {
+
+TEST_F(LayerHistoryTestV2, oneLayer) {
+ const auto layer = createLayer();
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+
+ // No layers returned if no layers are active.
+ EXPECT_TRUE(history().summarize(mTime).empty());
+ EXPECT_EQ(0, activeLayerCount());
+
+ // Max returned if active layers have insufficient history.
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) {
+ history().record(layer.get(), 0, mTime);
+ ASSERT_EQ(1, history().summarize(mTime).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(mTime)[0].vote);
+ EXPECT_EQ(1, activeLayerCount());
+ }
+
+ // Max is returned since we have enough history but there is no timestamp votes.
+ for (int i = 0; i < 10; i++) {
+ history().record(layer.get(), 0, mTime);
+ ASSERT_EQ(1, history().summarize(mTime).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(mTime)[0].vote);
+ EXPECT_EQ(1, activeLayerCount());
+ }
+}
+
+TEST_F(LayerHistoryTestV2, oneInvisibleLayer) {
+ const auto layer = createLayer();
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+
+ history().record(layer.get(), 0, mTime);
+ auto summary = history().summarize(mTime);
+ ASSERT_EQ(1, history().summarize(mTime).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(mTime)[0].vote);
+ EXPECT_EQ(1, activeLayerCount());
+
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(false));
+
+ summary = history().summarize(mTime);
+ EXPECT_TRUE(history().summarize(mTime).empty());
+ EXPECT_EQ(0, activeLayerCount());
+}
+
+TEST_F(LayerHistoryTestV2, explicitTimestamp) {
+ const auto layer = createLayer();
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+
+ nsecs_t time = mTime;
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer.get(), time, time);
+ time += LO_FPS_PERIOD;
+ }
+
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[0].vote);
+ EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryTestV2, oneLayerNoVote) {
+ const auto layer = createLayer();
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+
+ setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::NoVote);
+
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+
+ nsecs_t time = mTime;
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer.get(), time, time);
+ time += HI_FPS_PERIOD;
+ }
+
+ ASSERT_TRUE(history().summarize(time).empty());
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer became inactive
+ time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
+ ASSERT_TRUE(history().summarize(time).empty());
+ EXPECT_EQ(0, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryTestV2, oneLayerMinVote) {
+ const auto layer = createLayer();
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+
+ setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::Min);
+
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+
+ nsecs_t time = mTime;
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer.get(), time, time);
+ time += HI_FPS_PERIOD;
+ }
+
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer became inactive
+ time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
+ ASSERT_TRUE(history().summarize(time).empty());
+ EXPECT_EQ(0, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryTestV2, oneLayerMaxVote) {
+ const auto layer = createLayer();
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+
+ setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::Max);
+
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+
+ nsecs_t time = mTime;
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer.get(), time, time);
+ time += LO_FPS_PERIOD;
+ }
+
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer became inactive
+ time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
+ ASSERT_TRUE(history().summarize(time).empty());
+ EXPECT_EQ(0, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryTestV2, oneLayerExplicitVote) {
+ auto layer = createLayer();
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(73.4f));
+
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+
+ nsecs_t time = mTime;
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer.get(), time, time);
+ time += HI_FPS_PERIOD;
+ }
+
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Explicit, history().summarize(time)[0].vote);
+ EXPECT_FLOAT_EQ(73.4f, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer became inactive
+ setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::Heuristic);
+ time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
+ ASSERT_TRUE(history().summarize(time).empty());
+ // TODO: activeLayerCount() should be 0 but it is 1 since getFrameRate() returns a value > 0
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryTestV2, multipleLayers) {
+ auto layer1 = createLayer();
+ auto layer2 = createLayer();
+ auto layer3 = createLayer();
+
+ EXPECT_CALL(*layer1, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer1, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+
+ EXPECT_CALL(*layer2, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer2, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+
+ EXPECT_CALL(*layer3, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer3, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+
+ nsecs_t time = mTime;
+
+ EXPECT_EQ(3, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+
+ // layer1 is active but infrequent.
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer1.get(), time, time);
+ time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
+ }
+
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+
+ // layer2 is frequent and has high refresh rate.
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer2.get(), time, time);
+ time += HI_FPS_PERIOD;
+ }
+
+ // layer1 is still active but infrequent.
+ history().record(layer1.get(), time, time);
+
+ ASSERT_EQ(2, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
+ EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[1].vote);
+ EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time)[1].desiredRefreshRate);
+ EXPECT_EQ(2, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer1 is no longer active.
+ // layer2 is frequent and has low refresh rate.
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer2.get(), time, time);
+ time += LO_FPS_PERIOD;
+ }
+
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[0].vote);
+ EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer2 still has low refresh rate.
+ // layer3 has high refresh rate but not enough history.
+ constexpr int RATIO = LO_FPS_PERIOD / HI_FPS_PERIOD;
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) {
+ if (i % RATIO == 0) {
+ history().record(layer2.get(), time, time);
+ }
+
+ history().record(layer3.get(), time, time);
+ time += HI_FPS_PERIOD;
+ }
+
+ ASSERT_EQ(2, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[0].vote);
+ EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[1].vote);
+ EXPECT_EQ(2, activeLayerCount());
+ EXPECT_EQ(2, frequentLayerCount(time));
+
+ // layer3 becomes recently active.
+ history().record(layer3.get(), time, time);
+ ASSERT_EQ(2, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[0].vote);
+ EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[1].vote);
+ EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time)[1].desiredRefreshRate);
+ EXPECT_EQ(2, activeLayerCount());
+ EXPECT_EQ(2, frequentLayerCount(time));
+
+ // layer1 expires.
+ layer1.clear();
+ ASSERT_EQ(2, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[0].vote);
+ EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[0].vote);
+ EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[1].vote);
+ EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time)[1].desiredRefreshRate);
+ EXPECT_EQ(2, layerCount());
+ EXPECT_EQ(2, activeLayerCount());
+ EXPECT_EQ(2, frequentLayerCount(time));
+
+ // layer2 still has low refresh rate.
+ // layer3 becomes inactive.
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer2.get(), time, time);
+ time += LO_FPS_PERIOD;
+ }
+
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[0].vote);
+ EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer2 expires.
+ layer2.clear();
+ EXPECT_TRUE(history().summarize(time).empty());
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+
+ // layer3 becomes active and has high refresh rate.
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer3.get(), time, time);
+ time += HI_FPS_PERIOD;
+ }
+
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[0].vote);
+ EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer3 expires.
+ layer3.clear();
+ EXPECT_TRUE(history().summarize(time).empty());
+ EXPECT_EQ(0, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+}
+
+} // namespace
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp b/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp
index 6360ec1..910e73b 100644
--- a/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#undef LOG_TAG
#define LOG_TAG "SchedulerUnittests"
@@ -124,3 +128,6 @@
} // namespace
} // namespace scheduler
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index cc3c985..78009b8 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -31,16 +31,24 @@
namespace scheduler {
using RefreshRate = RefreshRateConfigs::RefreshRate;
+using LayerVoteType = RefreshRateConfigs::LayerVoteType;
+using LayerRequirement = RefreshRateConfigs::LayerRequirement;
class RefreshRateConfigsTest : public testing::Test {
protected:
static inline const HwcConfigIndexType HWC_CONFIG_ID_60 = HwcConfigIndexType(0);
- static inline const HwcConfigIndexType HWC_CONFIG_ID_90 = HwcConfigIndexType(1);
+ static inline const HwcConfigIndexType HWC_CONFIG_ID_72 = HwcConfigIndexType(1);
+ static inline const HwcConfigIndexType HWC_CONFIG_ID_90 = HwcConfigIndexType(2);
+ static inline const HwcConfigIndexType HWC_CONFIG_ID_120 = HwcConfigIndexType(3);
+ static inline const HwcConfigIndexType HWC_CONFIG_ID_30 = HwcConfigIndexType(4);
static inline const HwcConfigGroupType HWC_GROUP_ID_0 = HwcConfigGroupType(0);
static inline const HwcConfigGroupType HWC_GROUP_ID_1 = HwcConfigGroupType(1);
- static constexpr int64_t VSYNC_60 = 16666667;
+ static constexpr auto VSYNC_30 = static_cast<int64_t>(1e9f / 30);
+ static constexpr auto VSYNC_60 = static_cast<int64_t>(1e9f / 60);
+ static constexpr auto VSYNC_72 = static_cast<int64_t>(1e9f / 72);
+ static constexpr auto VSYNC_90 = static_cast<int64_t>(1e9f / 90);
+ static constexpr auto VSYNC_120 = static_cast<int64_t>(1e9f / 120);
static constexpr int64_t VSYNC_60_POINT_4 = 16666665;
- static constexpr int64_t VSYNC_90 = 11111111;
RefreshRateConfigsTest();
~RefreshRateConfigsTest();
@@ -212,41 +220,486 @@
RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
RefreshRate expected90Config = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", 90};
- ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(90.0f));
- ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(60.0f));
- ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(45.0f));
- ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(30.0f));
- ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(24.0f));
+ const auto makeLayerRequirements = [](float refreshRate) -> std::vector<LayerRequirement> {
+ return {{"testLayer", LayerVoteType::Heuristic, refreshRate, 1.0f}};
+ };
+
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f)));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(60.0f)));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(45.0f)));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(30.0f)));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f)));
ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 60, 60, nullptr), 0);
- ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(90.0f));
- ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(60.0f));
- ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(45.0f));
- ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(30.0f));
- ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(24.0f));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f)));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(60.0f)));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(45.0f)));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(30.0f)));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f)));
ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 90, 90, nullptr), 0);
- ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(90.0f));
- ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(60.0f));
- ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(45.0f));
- ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(30.0f));
- ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(24.0f));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f)));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(60.0f)));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(45.0f)));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(30.0f)));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f)));
ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 0, 120, nullptr), 0);
- ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(90.0f));
- ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(60.0f));
- ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(45.0f));
- ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(30.0f));
- ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(24.0f));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f)));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(60.0f)));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(45.0f)));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(30.0f)));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f)));
+}
+
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_60_90) {
+ std::vector<RefreshRateConfigs::InputConfig> configs{
+ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
+ {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+
+ RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
+ RefreshRate expected90Config = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", 90};
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& lr = layers[0];
+
+ lr.vote = LayerVoteType::Min;
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.vote = LayerVoteType::Max;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 90.0f;
+ lr.vote = LayerVoteType::Heuristic;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 60.0f;
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 45.0f;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 30.0f;
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 24.0f;
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 60, 60, nullptr), 0);
+
+ lr.vote = LayerVoteType::Min;
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.vote = LayerVoteType::Max;
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 90.0f;
+ lr.vote = LayerVoteType::Heuristic;
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 60.0f;
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 45.0f;
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 30.0f;
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 24.0f;
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 90, 90, nullptr), 0);
+
+ lr.vote = LayerVoteType::Min;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.vote = LayerVoteType::Max;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 90.0f;
+ lr.vote = LayerVoteType::Heuristic;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 60.0f;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 45.0f;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 30.0f;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 24.0f;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 0, 120, nullptr), 0);
+ lr.vote = LayerVoteType::Min;
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.vote = LayerVoteType::Max;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 90.0f;
+ lr.vote = LayerVoteType::Heuristic;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 60.0f;
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 45.0f;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 30.0f;
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 24.0f;
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+}
+
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_60_72_90) {
+ std::vector<RefreshRateConfigs::InputConfig> configs{
+ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
+ {HWC_CONFIG_ID_72, HWC_GROUP_ID_0, VSYNC_72},
+ {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+
+ RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
+ RefreshRate expected72Config = {HWC_CONFIG_ID_72, VSYNC_72, HWC_GROUP_ID_0, "72fps", 70};
+ RefreshRate expected90Config = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", 90};
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& lr = layers[0];
+
+ lr.vote = LayerVoteType::Min;
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.vote = LayerVoteType::Max;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 90.0f;
+ lr.vote = LayerVoteType::Heuristic;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 60.0f;
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 45.0f;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 30.0f;
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 24.0f;
+ EXPECT_EQ(expected72Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+}
+
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_30_60_72_90_120) {
+ std::vector<RefreshRateConfigs::InputConfig> configs{
+ {{HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30},
+ {HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
+ {HWC_CONFIG_ID_72, HWC_GROUP_ID_0, VSYNC_72},
+ {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90},
+ {HWC_CONFIG_ID_120, HWC_GROUP_ID_0, VSYNC_120}}};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+
+ RefreshRate expected30Config = {HWC_CONFIG_ID_30, VSYNC_30, HWC_GROUP_ID_0, "30fps", 30};
+ RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
+ RefreshRate expected72Config = {HWC_CONFIG_ID_72, VSYNC_72, HWC_GROUP_ID_0, "72fps", 70};
+ RefreshRate expected90Config = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", 90};
+ RefreshRate expected120Config = {HWC_CONFIG_ID_120, VSYNC_120, HWC_GROUP_ID_0, "120fps", 120};
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
+ LayerRequirement{.weight = 1.0f}};
+ auto& lr1 = layers[0];
+ auto& lr2 = layers[1];
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::Heuristic;
+ lr2.desiredRefreshRate = 60.0f;
+ lr2.vote = LayerVoteType::Heuristic;
+ EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::Heuristic;
+ lr2.desiredRefreshRate = 48.0f;
+ lr2.vote = LayerVoteType::Heuristic;
+ EXPECT_EQ(expected72Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::Heuristic;
+ lr2.desiredRefreshRate = 48.0f;
+ lr2.vote = LayerVoteType::Heuristic;
+ EXPECT_EQ(expected72Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+}
+
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_30_60) {
+ std::vector<RefreshRateConfigs::InputConfig> configs{
+ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
+ {HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30}}};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+
+ RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
+ RefreshRate expected30Config = {HWC_CONFIG_ID_30, VSYNC_30, HWC_GROUP_ID_0, "30fps", 30};
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& lr = layers[0];
+
+ lr.vote = LayerVoteType::Min;
+ EXPECT_EQ(expected30Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.vote = LayerVoteType::Max;
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 90.0f;
+ lr.vote = LayerVoteType::Heuristic;
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 60.0f;
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 45.0f;
+ EXPECT_EQ(expected30Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 30.0f;
+ EXPECT_EQ(expected30Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 24.0f;
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+}
+
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_30_60_72_90) {
+ std::vector<RefreshRateConfigs::InputConfig> configs{
+ {{HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30},
+ {HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
+ {HWC_CONFIG_ID_72, HWC_GROUP_ID_0, VSYNC_72},
+ {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+
+ RefreshRate expected30Config = {HWC_CONFIG_ID_30, VSYNC_30, HWC_GROUP_ID_0, "30fps", 30};
+ RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
+ RefreshRate expected72Config = {HWC_CONFIG_ID_72, VSYNC_72, HWC_GROUP_ID_0, "72fps", 70};
+ RefreshRate expected90Config = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", 90};
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& lr = layers[0];
+
+ lr.vote = LayerVoteType::Min;
+ EXPECT_EQ(expected30Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.vote = LayerVoteType::Max;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 90.0f;
+ lr.vote = LayerVoteType::Heuristic;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 60.0f;
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 45.0f;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 30.0f;
+ EXPECT_EQ(expected30Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr.desiredRefreshRate = 24.0f;
+ EXPECT_EQ(expected72Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+}
+
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_PriorityTest) {
+ std::vector<RefreshRateConfigs::InputConfig> configs{
+ {{HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30},
+ {HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
+ {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+
+ RefreshRate expected30Config = {HWC_CONFIG_ID_30, VSYNC_30, HWC_GROUP_ID_0, "30fps", 30};
+ RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
+ RefreshRate expected90Config = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", 90};
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
+ LayerRequirement{.weight = 1.0f}};
+ auto& lr1 = layers[0];
+ auto& lr2 = layers[1];
+
+ lr1.vote = LayerVoteType::Min;
+ lr2.vote = LayerVoteType::Max;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.vote = LayerVoteType::Min;
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.desiredRefreshRate = 24.0f;
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.vote = LayerVoteType::Min;
+ lr2.vote = LayerVoteType::Explicit;
+ lr2.desiredRefreshRate = 24.0f;
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.vote = LayerVoteType::Max;
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.desiredRefreshRate = 60.0f;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.vote = LayerVoteType::Max;
+ lr2.vote = LayerVoteType::Explicit;
+ lr2.desiredRefreshRate = 60.0f;
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.vote = LayerVoteType::Heuristic;
+ lr1.desiredRefreshRate = 15.0f;
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.desiredRefreshRate = 45.0f;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.vote = LayerVoteType::Heuristic;
+ lr1.desiredRefreshRate = 30.0f;
+ lr2.vote = LayerVoteType::Explicit;
+ lr2.desiredRefreshRate = 45.0f;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+}
+
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_24FpsVideo) {
+ std::vector<RefreshRateConfigs::InputConfig> configs{
+ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
+ {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+
+ RefreshRate expected30Config = {HWC_CONFIG_ID_30, VSYNC_30, HWC_GROUP_ID_0, "30fps", 30};
+ RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
+ RefreshRate expected90Config = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", 90};
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& lr = layers[0];
+
+ lr.vote = LayerVoteType::Explicit;
+ for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) {
+ lr.desiredRefreshRate = fps;
+ const auto& refreshRate = refreshRateConfigs->getRefreshRateForContentV2(layers);
+ printf("%.2fHz chooses %s\n", fps, refreshRate.name.c_str());
+ EXPECT_EQ(expected60Config, refreshRate);
+ }
+}
+
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContent_Explicit) {
+ std::vector<RefreshRateConfigs::InputConfig> configs{
+ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
+ {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+
+ RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
+ RefreshRate expected90Config = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", 90};
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
+ LayerRequirement{.weight = 1.0f}};
+ auto& lr1 = layers[0];
+ auto& lr2 = layers[1];
+
+ lr1.vote = LayerVoteType::Heuristic;
+ lr1.desiredRefreshRate = 60.0f;
+ lr2.vote = LayerVoteType::Explicit;
+ lr2.desiredRefreshRate = 90.0f;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(layers));
+
+ lr1.vote = LayerVoteType::Heuristic;
+ lr1.desiredRefreshRate = 90.0f;
+ lr2.vote = LayerVoteType::Explicit;
+ lr2.desiredRefreshRate = 60.0f;
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(layers));
+}
+
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_Explicit) {
+ std::vector<RefreshRateConfigs::InputConfig> configs{
+ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
+ {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+
+ RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
+ RefreshRate expected90Config = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", 90};
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
+ LayerRequirement{.weight = 1.0f}};
+ auto& lr1 = layers[0];
+ auto& lr2 = layers[1];
+
+ lr1.vote = LayerVoteType::Heuristic;
+ lr1.desiredRefreshRate = 60.0f;
+ lr2.vote = LayerVoteType::Explicit;
+ lr2.desiredRefreshRate = 90.0f;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.vote = LayerVoteType::Heuristic;
+ lr1.desiredRefreshRate = 90.0f;
+ lr2.vote = LayerVoteType::Explicit;
+ lr2.desiredRefreshRate = 60.0f;
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
}
TEST_F(RefreshRateConfigsTest, testInPolicy) {
RefreshRate expectedDefaultConfig = {HWC_CONFIG_ID_60, VSYNC_60_POINT_4, HWC_GROUP_ID_0,
"60fps", 60};
- ASSERT_TRUE(expectedDefaultConfig.inPolicy(60.000004, 60.000004));
+ ASSERT_TRUE(expectedDefaultConfig.inPolicy(60.000004f, 60.000004f));
ASSERT_TRUE(expectedDefaultConfig.inPolicy(59.0f, 60.1f));
- ASSERT_FALSE(expectedDefaultConfig.inPolicy(75.0, 90.0));
- ASSERT_FALSE(expectedDefaultConfig.inPolicy(60.0011, 90.0));
- ASSERT_FALSE(expectedDefaultConfig.inPolicy(50.0, 59.998));
+ ASSERT_FALSE(expectedDefaultConfig.inPolicy(75.0f, 90.0f));
+ ASSERT_FALSE(expectedDefaultConfig.inPolicy(60.0011f, 90.0f));
+ ASSERT_FALSE(expectedDefaultConfig.inPolicy(50.0f, 59.998f));
}
} // namespace
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
new file mode 100644
index 0000000..cffdc14
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
@@ -0,0 +1,290 @@
+/*
+ * 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <gui/LayerMetadata.h>
+
+#include "BufferQueueLayer.h"
+#include "BufferStateLayer.h"
+#include "ColorLayer.h"
+#include "Layer.h"
+#include "TestableSurfaceFlinger.h"
+#include "mock/DisplayHardware/MockComposer.h"
+#include "mock/MockDispSync.h"
+#include "mock/MockEventControlThread.h"
+#include "mock/MockEventThread.h"
+
+namespace android {
+
+using testing::_;
+using testing::DoAll;
+using testing::Mock;
+using testing::Return;
+using testing::SetArgPointee;
+
+using android::Hwc2::IComposer;
+using android::Hwc2::IComposerClient;
+
+using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+
+/**
+ * This class covers all the test that are related to refresh rate selection.
+ */
+class RefreshRateSelectionTest : public testing::Test {
+public:
+ RefreshRateSelectionTest();
+ ~RefreshRateSelectionTest() override;
+
+protected:
+ static constexpr int DEFAULT_DISPLAY_WIDTH = 1920;
+ static constexpr int DEFAULT_DISPLAY_HEIGHT = 1024;
+ static constexpr uint32_t WIDTH = 100;
+ static constexpr uint32_t HEIGHT = 100;
+ static constexpr uint32_t LAYER_FLAGS = 0;
+ static constexpr int32_t PRIORITY_UNSET = -1;
+
+ void setupScheduler();
+ void setupComposer(int virtualDisplayCount);
+ sp<BufferQueueLayer> createBufferQueueLayer();
+ sp<BufferStateLayer> createBufferStateLayer();
+ sp<ColorLayer> createColorLayer();
+
+ void setParent(Layer* child, Layer* parent);
+ void commitTransaction(Layer* layer);
+
+ TestableSurfaceFlinger mFlinger;
+ Hwc2::mock::Composer* mComposer = nullptr;
+
+ sp<Client> mClient;
+ sp<Layer> mParent;
+ sp<Layer> mChild;
+ sp<Layer> mGrandChild;
+};
+
+RefreshRateSelectionTest::RefreshRateSelectionTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+
+ setupScheduler();
+ setupComposer(0);
+}
+
+RefreshRateSelectionTest::~RefreshRateSelectionTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+}
+
+sp<BufferQueueLayer> RefreshRateSelectionTest::createBufferQueueLayer() {
+ sp<Client> client;
+ LayerCreationArgs args(mFlinger.flinger(), client, "buffer-queue-layer", WIDTH, HEIGHT,
+ LAYER_FLAGS, LayerMetadata());
+ return new BufferQueueLayer(args);
+}
+
+sp<BufferStateLayer> RefreshRateSelectionTest::createBufferStateLayer() {
+ sp<Client> client;
+ LayerCreationArgs args(mFlinger.flinger(), client, "buffer-queue-layer", WIDTH, HEIGHT,
+ LAYER_FLAGS, LayerMetadata());
+ return new BufferStateLayer(args);
+}
+
+sp<ColorLayer> RefreshRateSelectionTest::createColorLayer() {
+ sp<Client> client;
+ LayerCreationArgs args(mFlinger.flinger(), client, "color-layer", WIDTH, HEIGHT, LAYER_FLAGS,
+ LayerMetadata());
+ return new ColorLayer(args);
+}
+
+void RefreshRateSelectionTest::setParent(Layer* child, Layer* parent) {
+ child->setParent(parent);
+}
+
+void RefreshRateSelectionTest::commitTransaction(Layer* layer) {
+ layer->commitTransaction(layer->getCurrentState());
+}
+
+void RefreshRateSelectionTest::setupScheduler() {
+ auto eventThread = std::make_unique<mock::EventThread>();
+ auto sfEventThread = std::make_unique<mock::EventThread>();
+
+ EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*eventThread, createEventConnection(_, _))
+ .WillOnce(Return(new EventThreadConnection(eventThread.get(), ResyncCallback(),
+ ISurfaceComposer::eConfigChangedSuppress)));
+
+ EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
+ .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), ResyncCallback(),
+ ISurfaceComposer::eConfigChangedSuppress)));
+
+ auto primaryDispSync = std::make_unique<mock::DispSync>();
+
+ EXPECT_CALL(*primaryDispSync, computeNextRefresh(0)).WillRepeatedly(Return(0));
+ EXPECT_CALL(*primaryDispSync, getPeriod())
+ .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+ EXPECT_CALL(*primaryDispSync, expectedPresentTime()).WillRepeatedly(Return(0));
+ mFlinger.setupScheduler(std::move(primaryDispSync),
+ std::make_unique<mock::EventControlThread>(), std::move(eventThread),
+ std::move(sfEventThread));
+}
+
+void RefreshRateSelectionTest::setupComposer(int virtualDisplayCount) {
+ mComposer = new Hwc2::mock::Composer();
+ EXPECT_CALL(*mComposer, getCapabilities())
+ .WillOnce(Return(std::vector<IComposer::Capability>()));
+ EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
+ mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
+
+ Mock::VerifyAndClear(mComposer);
+}
+
+namespace {
+/* ------------------------------------------------------------------------
+ * Test cases
+ */
+TEST_F(RefreshRateSelectionTest, testPriorityOnBufferQueueLayers) {
+ mParent = createBufferQueueLayer();
+ mChild = createBufferQueueLayer();
+ setParent(mChild.get(), mParent.get());
+ mGrandChild = createBufferQueueLayer();
+ setParent(mGrandChild.get(), mChild.get());
+
+ ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+ ASSERT_EQ(PRIORITY_UNSET, mChild->getFrameRateSelectionPriority());
+ ASSERT_EQ(PRIORITY_UNSET, mGrandChild->getFrameRateSelectionPriority());
+
+ // Child has its own priority.
+ mGrandChild->setFrameRateSelectionPriority(1);
+ commitTransaction(mGrandChild.get());
+ ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+ ASSERT_EQ(PRIORITY_UNSET, mChild->getFrameRateSelectionPriority());
+ ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+
+ // Child inherits from his parent.
+ mChild->setFrameRateSelectionPriority(1);
+ commitTransaction(mChild.get());
+ mGrandChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+ commitTransaction(mGrandChild.get());
+
+ ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+ ASSERT_EQ(1, mChild->getFrameRateSelectionPriority());
+ ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+
+ // Grandchild inherits from his grand parent.
+ mParent->setFrameRateSelectionPriority(1);
+ commitTransaction(mParent.get());
+ mChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+ commitTransaction(mChild.get());
+ mGrandChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+ commitTransaction(mGrandChild.get());
+ ASSERT_EQ(1, mParent->getFrameRateSelectionPriority());
+ ASSERT_EQ(1, mChild->getFrameRateSelectionPriority());
+ ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+}
+
+TEST_F(RefreshRateSelectionTest, testPriorityOnBufferStateLayers) {
+ mParent = createBufferStateLayer();
+ mChild = createBufferStateLayer();
+ setParent(mChild.get(), mParent.get());
+ mGrandChild = createBufferStateLayer();
+ setParent(mGrandChild.get(), mChild.get());
+
+ ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+ ASSERT_EQ(PRIORITY_UNSET, mChild->getFrameRateSelectionPriority());
+ ASSERT_EQ(PRIORITY_UNSET, mGrandChild->getFrameRateSelectionPriority());
+
+ // Child has its own priority.
+ mGrandChild->setFrameRateSelectionPriority(1);
+ commitTransaction(mGrandChild.get());
+ ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+ ASSERT_EQ(PRIORITY_UNSET, mChild->getFrameRateSelectionPriority());
+ ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+
+ // Child inherits from his parent.
+ mChild->setFrameRateSelectionPriority(1);
+ commitTransaction(mChild.get());
+ mGrandChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+ commitTransaction(mGrandChild.get());
+ ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+ ASSERT_EQ(1, mChild->getFrameRateSelectionPriority());
+ ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+
+ // Grandchild inherits from his grand parent.
+ mParent->setFrameRateSelectionPriority(1);
+ commitTransaction(mParent.get());
+ mChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+ commitTransaction(mChild.get());
+ mGrandChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+ commitTransaction(mGrandChild.get());
+ ASSERT_EQ(1, mParent->getFrameRateSelectionPriority());
+ ASSERT_EQ(1, mChild->getFrameRateSelectionPriority());
+ ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+}
+
+TEST_F(RefreshRateSelectionTest, testPriorityOnColorLayers) {
+ mParent = createColorLayer();
+ mChild = createColorLayer();
+ setParent(mChild.get(), mParent.get());
+ mGrandChild = createColorLayer();
+ setParent(mGrandChild.get(), mChild.get());
+
+ ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+ ASSERT_EQ(PRIORITY_UNSET, mChild->getFrameRateSelectionPriority());
+ ASSERT_EQ(PRIORITY_UNSET, mGrandChild->getFrameRateSelectionPriority());
+
+ // Child has its own priority.
+ mGrandChild->setFrameRateSelectionPriority(1);
+ commitTransaction(mGrandChild.get());
+ ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+ ASSERT_EQ(PRIORITY_UNSET, mChild->getFrameRateSelectionPriority());
+ ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+
+ // Child inherits from his parent.
+ mChild->setFrameRateSelectionPriority(1);
+ commitTransaction(mChild.get());
+ mGrandChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+ commitTransaction(mGrandChild.get());
+ ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+ ASSERT_EQ(1, mChild->getFrameRateSelectionPriority());
+ ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+
+ // Grandchild inherits from his grand parent.
+ mParent->setFrameRateSelectionPriority(1);
+ commitTransaction(mParent.get());
+ mChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+ commitTransaction(mChild.get());
+ mGrandChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+ commitTransaction(mGrandChild.get());
+ ASSERT_EQ(1, mParent->getFrameRateSelectionPriority());
+ ASSERT_EQ(1, mChild->getFrameRateSelectionPriority());
+ ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+}
+
+} // namespace
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
index ef4699f..8e07c79 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#undef LOG_TAG
#define LOG_TAG "SchedulerUnittests"
@@ -195,3 +199,6 @@
} // namespace
} // namespace scheduler
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp b/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp
index d8de804..f19e554 100644
--- a/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#undef LOG_TAG
#define LOG_TAG "RegionSamplingTest"
@@ -137,3 +141,6 @@
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 40536ab..82a00ee 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -1,3 +1,23 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#undef LOG_TAG
#define LOG_TAG "SchedulerUnittests"
@@ -56,7 +76,7 @@
scheduler::RefreshRateConfigs>(/*refreshRateSwitching=*/false, configs,
/*currentConfig=*/HwcConfigIndexType(0));
- mScheduler = std::make_unique<TestableScheduler>(*mRefreshRateConfigs);
+ mScheduler = std::make_unique<TestableScheduler>(*mRefreshRateConfigs, false);
auto eventThread = std::make_unique<mock::EventThread>();
mEventThread = eventThread.get();
@@ -144,3 +164,6 @@
} // namespace
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/SchedulerUtilsTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerUtilsTest.cpp
index 5865579..5f6a715 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerUtilsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerUtilsTest.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#undef LOG_TAG
#define LOG_TAG "SchedulerUnittests"
@@ -128,4 +132,6 @@
} // namespace
} // namespace scheduler
-} // namespace android
\ No newline at end of file
+} // namespace android
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index a67c24c..52da34b 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -28,16 +28,25 @@
class TestableScheduler : public Scheduler, private ISchedulerCallback {
public:
- explicit TestableScheduler(const scheduler::RefreshRateConfigs& configs)
- : Scheduler([](bool) {}, configs, *this) {
- mLayerHistory = std::make_unique<scheduler::impl::LayerHistory>();
+ TestableScheduler(const scheduler::RefreshRateConfigs& configs, bool useContentDetectionV2)
+ : Scheduler([](bool) {}, configs, *this, useContentDetectionV2) {
+ if (mUseContentDetectionV2) {
+ mLayerHistory = std::make_unique<scheduler::impl::LayerHistoryV2>();
+ } else {
+ mLayerHistory = std::make_unique<scheduler::impl::LayerHistory>();
+ }
}
TestableScheduler(std::unique_ptr<DispSync> primaryDispSync,
std::unique_ptr<EventControlThread> eventControlThread,
- const scheduler::RefreshRateConfigs& configs)
- : Scheduler(std::move(primaryDispSync), std::move(eventControlThread), configs, *this) {
- mLayerHistory = std::make_unique<scheduler::impl::LayerHistory>();
+ const scheduler::RefreshRateConfigs& configs, bool useContentDetectionV2)
+ : Scheduler(std::move(primaryDispSync), std::move(eventControlThread), configs, *this,
+ useContentDetectionV2) {
+ if (mUseContentDetectionV2) {
+ mLayerHistory = std::make_unique<scheduler::impl::LayerHistoryV2>();
+ } else {
+ mLayerHistory = std::make_unique<scheduler::impl::LayerHistory>();
+ }
}
// Used to inject mock event thread.
@@ -46,7 +55,13 @@
}
size_t layerHistorySize() const NO_THREAD_SAFETY_ANALYSIS {
- return static_cast<scheduler::impl::LayerHistory*>(mLayerHistory.get())->mLayerInfos.size();
+ if (mUseContentDetectionV2) {
+ return static_cast<scheduler::impl::LayerHistoryV2*>(mLayerHistory.get())
+ ->mLayerInfos.size();
+ } else {
+ return static_cast<scheduler::impl::LayerHistory*>(mLayerHistory.get())
+ ->mLayerInfos.size();
+ }
}
/* ------------------------------------------------------------------------
@@ -60,6 +75,9 @@
auto mutableLayerHistory() {
return static_cast<scheduler::impl::LayerHistory*>(mLayerHistory.get());
}
+ auto mutableLayerHistoryV2() {
+ return static_cast<scheduler::impl::LayerHistoryV2*>(mLayerHistory.get());
+ }
~TestableScheduler() {
// All these pointer and container clears help ensure that GMock does
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 9728c80..2491533 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -198,7 +198,8 @@
void setupScheduler(std::unique_ptr<DispSync> primaryDispSync,
std::unique_ptr<EventControlThread> eventControlThread,
std::unique_ptr<EventThread> appEventThread,
- std::unique_ptr<EventThread> sfEventThread) {
+ std::unique_ptr<EventThread> sfEventThread,
+ bool useContentDetectionV2 = false) {
std::vector<scheduler::RefreshRateConfigs::InputConfig> configs{
{{HwcConfigIndexType(0), HwcConfigGroupType(0), 16666667}}};
mFlinger->mRefreshRateConfigs = std::make_unique<
@@ -213,7 +214,7 @@
mScheduler =
new TestableScheduler(std::move(primaryDispSync), std::move(eventControlThread),
- *mFlinger->mRefreshRateConfigs);
+ *mFlinger->mRefreshRateConfigs, useContentDetectionV2);
mFlinger->mAppConnectionHandle = mScheduler->createConnection(std::move(appEventThread));
mFlinger->mSfConnectionHandle = mScheduler->createConnection(std::move(sfEventThread));
@@ -443,7 +444,7 @@
static constexpr int32_t DEFAULT_REFRESH_RATE = 16'666'666;
static constexpr int32_t DEFAULT_CONFIG_GROUP = 7;
static constexpr int32_t DEFAULT_DPI = 320;
- static constexpr int32_t DEFAULT_ACTIVE_CONFIG = 0;
+ static constexpr hwc2_config_t DEFAULT_ACTIVE_CONFIG = 0;
static constexpr int32_t DEFAULT_POWER_MODE = 2;
FakeHwcDisplayInjector(DisplayId displayId, HWC2::DisplayType hwcDisplayType,
@@ -465,7 +466,7 @@
return *this;
}
- auto& setRefreshRate(uint32_t refreshRate) {
+ auto& setRefreshRate(int32_t refreshRate) {
mRefreshRate = refreshRate;
return *this;
}
@@ -480,7 +481,7 @@
return *this;
}
- auto& setActiveConfig(int32_t config) {
+ auto& setActiveConfig(hwc2_config_t config) {
mActiveConfig = config;
return *this;
}
@@ -513,7 +514,7 @@
config.setDpiX(mDpiX);
config.setDpiY(mDpiY);
config.setConfigGroup(mConfigGroup);
- display->mutableConfigs().emplace(mActiveConfig, config.build());
+ display->mutableConfigs().emplace(static_cast<int32_t>(mActiveConfig), config.build());
display->mutableIsConnected() = true;
display->setPowerMode(static_cast<HWC2::PowerMode>(mPowerMode));
@@ -534,11 +535,11 @@
hwc2_display_t mHwcDisplayId = DEFAULT_HWC_DISPLAY_ID;
int32_t mWidth = DEFAULT_WIDTH;
int32_t mHeight = DEFAULT_HEIGHT;
- uint32_t mRefreshRate = DEFAULT_REFRESH_RATE;
+ int32_t mRefreshRate = DEFAULT_REFRESH_RATE;
int32_t mDpiX = DEFAULT_DPI;
int32_t mConfigGroup = DEFAULT_CONFIG_GROUP;
int32_t mDpiY = DEFAULT_DPI;
- int32_t mActiveConfig = DEFAULT_ACTIVE_CONFIG;
+ hwc2_config_t mActiveConfig = DEFAULT_ACTIVE_CONFIG;
int32_t mPowerMode = DEFAULT_POWER_MODE;
const std::unordered_set<HWC2::Capability>* mCapabilities = nullptr;
};
@@ -605,6 +606,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 3e808c0..68e6697 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -14,10 +14,15 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"
#include <TimeStats/TimeStats.h>
+#include <android/util/ProtoOutputStream.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <log/log.h>
@@ -36,8 +41,13 @@
namespace android {
namespace {
+using testing::_;
+using testing::AnyNumber;
using testing::Contains;
+using testing::HasSubstr;
+using testing::InSequence;
using testing::SizeIs;
+using testing::StrEq;
using testing::UnorderedElementsAre;
// clang-format off
@@ -132,7 +142,42 @@
}
std::mt19937 mRandomEngine = std::mt19937(std::random_device()());
- std::unique_ptr<TimeStats> mTimeStats = std::make_unique<impl::TimeStats>();
+
+ class FakeStatsEventDelegate : public impl::TimeStats::StatsEventDelegate {
+ public:
+ FakeStatsEventDelegate() = default;
+ ~FakeStatsEventDelegate() override = default;
+
+ struct stats_event* addStatsEventToPullData(pulled_stats_event_list*) override {
+ return mEvent;
+ }
+ void registerStatsPullAtomCallback(int32_t atom_tag, stats_pull_atom_callback_t callback,
+ pull_atom_metadata*, void* cookie) override {
+ mAtomTags.push_back(atom_tag);
+ mCallback = callback;
+ mCookie = cookie;
+ }
+
+ status_pull_atom_return_t makePullAtomCallback(int32_t atom_tag, void* cookie) {
+ return (*mCallback)(atom_tag, nullptr, cookie);
+ }
+
+ MOCK_METHOD1(unregisterStatsPullAtomCallback, void(int32_t));
+ MOCK_METHOD2(statsEventSetAtomId, void(struct stats_event*, uint32_t));
+ MOCK_METHOD2(statsEventWriteInt64, void(struct stats_event*, int64_t));
+ MOCK_METHOD2(statsEventWriteString8, void(struct stats_event*, const char*));
+ MOCK_METHOD3(statsEventWriteByteArray, void(struct stats_event*, const uint8_t*, size_t));
+ MOCK_METHOD1(statsEventBuild, void(struct stats_event*));
+
+ struct stats_event* mEvent = stats_event_obtain();
+ std::vector<int32_t> mAtomTags;
+ stats_pull_atom_callback_t mCallback = nullptr;
+ void* mCookie = nullptr;
+ };
+ FakeStatsEventDelegate* mDelegate = new FakeStatsEventDelegate;
+ std::unique_ptr<TimeStats> mTimeStats =
+ std::make_unique<impl::TimeStats>(std::unique_ptr<FakeStatsEventDelegate>(mDelegate),
+ std::nullopt, std::nullopt);
};
std::string TimeStatsTest::inputCommand(InputCommand cmd, bool useProto) {
@@ -209,14 +254,26 @@
return distr(mRandomEngine);
}
-TEST_F(TimeStatsTest, enabledByDefault) {
+TEST_F(TimeStatsTest, disabledByDefault) {
+ ASSERT_FALSE(mTimeStats->isEnabled());
+}
+
+TEST_F(TimeStatsTest, enabledAfterBoot) {
+ mTimeStats->onBootFinished();
ASSERT_TRUE(mTimeStats->isEnabled());
}
TEST_F(TimeStatsTest, canEnableAndDisableTimeStats) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
ASSERT_TRUE(mTimeStats->isEnabled());
+ EXPECT_THAT(mDelegate->mAtomTags,
+ UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+ EXPECT_CALL(*mDelegate,
+ unregisterStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO));
+ EXPECT_CALL(*mDelegate,
+ unregisterStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO));
EXPECT_TRUE(inputCommand(InputCommand::DISABLE, FMT_STRING).empty());
ASSERT_FALSE(mTimeStats->isEnabled());
}
@@ -249,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());
@@ -593,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());
@@ -627,6 +709,319 @@
ASSERT_EQ(0, globalProto.stats_size());
}
+TEST_F(TimeStatsTest, globalStatsCallback) {
+ constexpr size_t TOTAL_FRAMES = 5;
+ constexpr size_t MISSED_FRAMES = 4;
+ constexpr size_t CLIENT_COMPOSITION_FRAMES = 3;
+
+ mTimeStats->onBootFinished();
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+ for (size_t i = 0; i < TOTAL_FRAMES; i++) {
+ mTimeStats->incrementTotalFrames();
+ }
+ for (size_t i = 0; i < MISSED_FRAMES; i++) {
+ mTimeStats->incrementMissedFrames();
+ }
+ for (size_t i = 0; i < CLIENT_COMPOSITION_FRAMES; i++) {
+ mTimeStats->incrementClientCompositionFrames();
+ }
+
+ mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+ mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
+ mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
+
+ EXPECT_THAT(mDelegate->mAtomTags,
+ UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+ EXPECT_NE(nullptr, mDelegate->mCallback);
+ EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
+
+ {
+ InSequence seq;
+ EXPECT_CALL(*mDelegate,
+ statsEventSetAtomId(mDelegate->mEvent,
+ android::util::SURFACEFLINGER_STATS_GLOBAL_INFO));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, TOTAL_FRAMES));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, MISSED_FRAMES));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, CLIENT_COMPOSITION_FRAMES));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, _));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 2));
+ EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
+ }
+ EXPECT_EQ(STATS_PULL_SUCCESS,
+ mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ mDelegate->mCookie));
+
+ SFTimeStatsGlobalProto globalProto;
+ ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
+
+ EXPECT_EQ(0, globalProto.total_frames());
+ EXPECT_EQ(0, globalProto.missed_frames());
+ EXPECT_EQ(0, globalProto.client_composition_frames());
+ EXPECT_EQ(0, globalProto.present_to_present_size());
+}
+
+namespace {
+std::string buildExpectedHistogramBytestring(const std::vector<int32_t>& times,
+ const std::vector<int32_t>& frameCounts) {
+ util::ProtoOutputStream proto;
+ for (int i = 0; i < times.size(); i++) {
+ ALOGE("Writing time: %d", times[i]);
+ proto.write(util::FIELD_TYPE_INT32 | util::FIELD_COUNT_REPEATED | 1 /* field id */,
+ (int32_t)times[i]);
+ ALOGE("Writing count: %d", frameCounts[i]);
+ proto.write(util::FIELD_TYPE_INT64 | util::FIELD_COUNT_REPEATED | 2 /* field id */,
+ (int64_t)frameCounts[i]);
+ }
+ std::string byteString;
+ proto.serializeToString(&byteString);
+ return byteString;
+}
+
+std::string dumpByteStringHex(const std::string& str) {
+ std::stringstream ss;
+ ss << std::hex;
+ for (const char& c : str) {
+ ss << (int)c << " ";
+ }
+
+ return ss.str();
+}
+
+} // namespace
+
+MATCHER_P2(BytesEq, bytes, size, "") {
+ std::string expected;
+ expected.append((const char*)bytes, size);
+ std::string actual;
+ actual.append((const char*)arg, size);
+
+ *result_listener << "Bytes are not equal! \n";
+ *result_listener << "size: " << size << "\n";
+ *result_listener << "expected: " << dumpByteStringHex(expected).c_str() << "\n";
+ *result_listener << "actual: " << dumpByteStringHex(actual).c_str() << "\n";
+
+ return expected == actual;
+}
+
+TEST_F(TimeStatsTest, layerStatsCallback_pullsAllHistogramsAndClears) {
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+ mTimeStats->onBootFinished();
+
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
+
+ EXPECT_THAT(mDelegate->mAtomTags,
+ UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+ EXPECT_NE(nullptr, mDelegate->mCallback);
+ EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
+
+ std::string expectedPresentToPresent = buildExpectedHistogramBytestring({1}, {1});
+ std::string expectedPostToPresent = buildExpectedHistogramBytestring({4}, {1});
+ std::string expectedAcquireToPresent = buildExpectedHistogramBytestring({3}, {1});
+ std::string expectedLatchToPresent = buildExpectedHistogramBytestring({2}, {1});
+ std::string expectedDesiredToPresent = buildExpectedHistogramBytestring({1}, {1});
+ std::string expectedPostToAcquire = buildExpectedHistogramBytestring({1}, {1});
+ {
+ InSequence seq;
+ EXPECT_CALL(*mDelegate,
+ statsEventSetAtomId(mDelegate->mEvent,
+ android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+ EXPECT_CALL(*mDelegate,
+ statsEventWriteString8(mDelegate->mEvent,
+ StrEq(genLayerName(LAYER_ID_0).c_str())));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 1));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 0));
+ EXPECT_CALL(*mDelegate,
+ statsEventWriteByteArray(mDelegate->mEvent,
+ BytesEq((const uint8_t*)
+ expectedPresentToPresent.c_str(),
+ expectedPresentToPresent.size()),
+ expectedPresentToPresent.size()));
+ EXPECT_CALL(*mDelegate,
+ statsEventWriteByteArray(mDelegate->mEvent,
+ BytesEq((const uint8_t*)expectedPostToPresent.c_str(),
+ expectedPostToPresent.size()),
+ expectedPostToPresent.size()));
+ EXPECT_CALL(*mDelegate,
+ statsEventWriteByteArray(mDelegate->mEvent,
+ BytesEq((const uint8_t*)
+ expectedAcquireToPresent.c_str(),
+ expectedAcquireToPresent.size()),
+ expectedAcquireToPresent.size()));
+ EXPECT_CALL(*mDelegate,
+ statsEventWriteByteArray(mDelegate->mEvent,
+ BytesEq((const uint8_t*)expectedLatchToPresent.c_str(),
+ expectedLatchToPresent.size()),
+ expectedLatchToPresent.size()));
+ EXPECT_CALL(*mDelegate,
+ statsEventWriteByteArray(mDelegate->mEvent,
+ BytesEq((const uint8_t*)
+ expectedDesiredToPresent.c_str(),
+ expectedDesiredToPresent.size()),
+ expectedDesiredToPresent.size()));
+ EXPECT_CALL(*mDelegate,
+ statsEventWriteByteArray(mDelegate->mEvent,
+ BytesEq((const uint8_t*)expectedPostToAcquire.c_str(),
+ expectedPostToAcquire.size()),
+ expectedPostToAcquire.size()));
+ EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
+ }
+ EXPECT_EQ(STATS_PULL_SUCCESS,
+ mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
+ mDelegate->mCookie));
+
+ SFTimeStatsGlobalProto globalProto;
+ ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
+
+ EXPECT_EQ(0, globalProto.stats_size());
+}
+
+TEST_F(TimeStatsTest, layerStatsCallback_pullsMultipleLayers) {
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+ mTimeStats->onBootFinished();
+
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 1, 2000000);
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 2, 3000000);
+
+ EXPECT_THAT(mDelegate->mAtomTags,
+ UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+ EXPECT_NE(nullptr, mDelegate->mCallback);
+ EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
+
+ EXPECT_CALL(*mDelegate,
+ statsEventSetAtomId(mDelegate->mEvent,
+ android::util::SURFACEFLINGER_STATS_LAYER_INFO))
+ .Times(2);
+ EXPECT_CALL(*mDelegate,
+ statsEventWriteString8(mDelegate->mEvent, StrEq(genLayerName(LAYER_ID_0).c_str())));
+ EXPECT_CALL(*mDelegate,
+ statsEventWriteString8(mDelegate->mEvent, StrEq(genLayerName(LAYER_ID_1).c_str())));
+ EXPECT_EQ(STATS_PULL_SUCCESS,
+ mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
+ mDelegate->mCookie));
+}
+
+TEST_F(TimeStatsTest, layerStatsCallback_pullsMultipleBuckets) {
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+ mTimeStats->onBootFinished();
+
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 4000000);
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 4, 5000000);
+
+ // Now make sure that TimeStats flushes global stats to register the
+ // callback.
+ mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+ mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
+ mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
+ EXPECT_THAT(mDelegate->mAtomTags,
+ UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+ EXPECT_NE(nullptr, mDelegate->mCallback);
+ EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
+
+ EXPECT_THAT(mDelegate->mAtomTags,
+ UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+ std::string expectedPresentToPresent = buildExpectedHistogramBytestring({1, 2}, {2, 1});
+ {
+ InSequence seq;
+ EXPECT_CALL(*mDelegate,
+ statsEventWriteByteArray(mDelegate->mEvent,
+ BytesEq((const uint8_t*)
+ expectedPresentToPresent.c_str(),
+ expectedPresentToPresent.size()),
+ expectedPresentToPresent.size()));
+ EXPECT_CALL(*mDelegate, statsEventWriteByteArray(mDelegate->mEvent, _, _))
+ .Times(AnyNumber());
+ }
+ EXPECT_EQ(STATS_PULL_SUCCESS,
+ mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
+ mDelegate->mCookie));
+}
+
+TEST_F(TimeStatsTest, layerStatsCallback_limitsHistogramBuckets) {
+ mDelegate = new FakeStatsEventDelegate;
+ mTimeStats =
+ std::make_unique<impl::TimeStats>(std::unique_ptr<FakeStatsEventDelegate>(mDelegate),
+ std::nullopt, 1);
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+ mTimeStats->onBootFinished();
+
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 4000000);
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 4, 5000000);
+
+ EXPECT_THAT(mDelegate->mAtomTags,
+ UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+ EXPECT_NE(nullptr, mDelegate->mCallback);
+ EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
+
+ EXPECT_THAT(mDelegate->mAtomTags,
+ UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+ std::string expectedPresentToPresent = buildExpectedHistogramBytestring({1}, {2});
+ {
+ InSequence seq;
+ EXPECT_CALL(*mDelegate,
+ statsEventWriteByteArray(mDelegate->mEvent,
+ BytesEq((const uint8_t*)
+ expectedPresentToPresent.c_str(),
+ expectedPresentToPresent.size()),
+ expectedPresentToPresent.size()));
+ EXPECT_CALL(*mDelegate, statsEventWriteByteArray(mDelegate->mEvent, _, _))
+ .Times(AnyNumber());
+ }
+ EXPECT_EQ(STATS_PULL_SUCCESS,
+ mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
+ mDelegate->mCookie));
+}
+
+TEST_F(TimeStatsTest, layerStatsCallback_limitsLayers) {
+ mDelegate = new FakeStatsEventDelegate;
+ mTimeStats =
+ std::make_unique<impl::TimeStats>(std::unique_ptr<FakeStatsEventDelegate>(mDelegate), 1,
+ std::nullopt);
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+ mTimeStats->onBootFinished();
+
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 1, 2000000);
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 2, 3000000);
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 4, 5000000);
+
+ EXPECT_THAT(mDelegate->mAtomTags,
+ UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+ EXPECT_NE(nullptr, mDelegate->mCallback);
+ EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
+
+ EXPECT_CALL(*mDelegate,
+ statsEventSetAtomId(mDelegate->mEvent,
+ android::util::SURFACEFLINGER_STATS_LAYER_INFO))
+ .Times(1);
+ EXPECT_CALL(*mDelegate,
+ statsEventWriteString8(mDelegate->mEvent, StrEq(genLayerName(LAYER_ID_1).c_str())));
+ EXPECT_EQ(STATS_PULL_SUCCESS,
+ mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
+ mDelegate->mCookie));
+}
+
TEST_F(TimeStatsTest, canSurviveMonkey) {
if (g_noSlowTests) {
GTEST_SKIP();
@@ -656,3 +1051,6 @@
} // namespace
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index 994a509..f1739e5 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#undef LOG_TAG
#define LOG_TAG "CompositionTest"
@@ -321,3 +325,6 @@
EXPECT_EQ(nullptr, ret.get());
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
index b51a025..acf852d 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
@@ -50,6 +50,7 @@
nsecs_t currentPeriod() const final { return mPeriod; }
void setPeriod(nsecs_t) final {}
+ void resetModel() final {}
private:
nsecs_t const mPeriod;
@@ -83,6 +84,7 @@
}
void setPeriod(nsecs_t) final {}
+ void resetModel() final {}
private:
std::mutex mutable mMutex;
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
index 6fcb1af..70c9225 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"
#define LOG_NDEBUG 0
@@ -41,6 +45,7 @@
MOCK_CONST_METHOD1(nextAnticipatedVSyncTimeFrom, nsecs_t(nsecs_t));
MOCK_CONST_METHOD0(currentPeriod, nsecs_t());
MOCK_METHOD1(setPeriod, void(nsecs_t));
+ MOCK_METHOD0(resetModel, void());
nsecs_t nextVSyncTime(nsecs_t timePoint) const {
if (timePoint % mPeriod == 0) {
@@ -809,3 +814,6 @@
}
} // namespace android::scheduler
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
index 4cb6a38..6ec3844 100644
--- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"
#define LOG_NDEBUG 0
@@ -351,4 +355,22 @@
EXPECT_THAT(prediction, Ge(timePoint));
}
+TEST_F(VSyncPredictorTest, resetsWhenInstructed) {
+ auto const idealPeriod = 10000;
+ auto const realPeriod = 10500;
+ tracker.setPeriod(idealPeriod);
+ for (auto i = 0; i < kMinimumSamplesForPrediction; i++) {
+ tracker.addVsyncTimestamp(i * realPeriod);
+ }
+
+ EXPECT_THAT(std::get<0>(tracker.getVSyncPredictionModel()),
+ IsCloseTo(realPeriod, mMaxRoundingError));
+ tracker.resetModel();
+ EXPECT_THAT(std::get<0>(tracker.getVSyncPredictionModel()),
+ IsCloseTo(idealPeriod, mMaxRoundingError));
+}
+
} // namespace android::scheduler
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
index 188adea..ce1fafe 100644
--- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -39,6 +39,7 @@
MOCK_CONST_METHOD1(nextAnticipatedVSyncTimeFrom, nsecs_t(nsecs_t));
MOCK_CONST_METHOD0(currentPeriod, nsecs_t());
MOCK_METHOD1(setPeriod, void(nsecs_t));
+ MOCK_METHOD0(resetModel, void());
};
class VSyncTrackerWrapper : public VSyncTracker {
@@ -50,7 +51,8 @@
return mTracker->nextAnticipatedVSyncTimeFrom(timePoint);
}
nsecs_t currentPeriod() const final { return mTracker->currentPeriod(); }
- void setPeriod(nsecs_t period) { mTracker->setPeriod(period); }
+ void setPeriod(nsecs_t period) final { mTracker->setPeriod(period); }
+ void resetModel() final { mTracker->resetModel(); }
private:
std::shared_ptr<VSyncTracker> const mTracker;
@@ -559,6 +561,11 @@
mReactor.addEventListener(mName, negativePhase, &outerCb, lastCallbackTime);
}
+TEST_F(VSyncReactorTest, beginResyncResetsModel) {
+ EXPECT_CALL(*mMockTracker, resetModel());
+ mReactor.beginResync();
+}
+
using VSyncReactorDeathTest = VSyncReactorTest;
TEST_F(VSyncReactorDeathTest, invalidRemoval) {
mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp
index 7ed57b9..0780af1 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include "mock/DisplayHardware/MockComposer.h"
namespace android {
@@ -27,3 +31,6 @@
} // namespace mock
} // namespace Hwc2
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index 0f9dd5b..5cbba81 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -134,6 +134,11 @@
MOCK_METHOD2(getSupportedContentTypes,
V2_4::Error(Display, std::vector<IComposerClient::ContentType>*));
MOCK_METHOD2(setContentType, V2_4::Error(Display, IComposerClient::ContentType));
+ MOCK_METHOD5(setLayerGenericMetadata,
+ V2_4::Error(Display, Layer, const std::string&, bool,
+ const std::vector<uint8_t>&));
+ MOCK_METHOD1(getLayerGenericMetadataKeys,
+ V2_4::Error(std::vector<IComposerClient::LayerGenericMetadataKey>*));
};
} // namespace mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
index f375e23..494e73d 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
@@ -28,8 +28,10 @@
: Layer(LayerCreationArgs(flinger, nullptr, "TestLayer", 800, 600, 0, {})) {}
MOCK_CONST_METHOD0(getType, const char*());
+ MOCK_METHOD0(getFrameSelectionPriority, int32_t());
MOCK_CONST_METHOD0(isVisible, bool());
MOCK_METHOD0(createClone, sp<Layer>());
+ MOCK_CONST_METHOD0(getFrameRate, std::optional<float>());
};
} // namespace android::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.cpp b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.cpp
index 4129328..7e925b9 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include "mock/MockSurfaceInterceptor.h"
namespace android {
@@ -25,3 +29,6 @@
} // namespace mock
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
index ec74a42..d1df08c 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
@@ -28,12 +28,14 @@
TimeStats();
~TimeStats() override;
+ MOCK_METHOD0(onBootFinished, void());
MOCK_METHOD3(parseArgs, void(bool, const Vector<String16>&, std::string&));
MOCK_METHOD0(isEnabled, bool());
MOCK_METHOD0(miniDump, std::string());
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>&));
diff --git a/services/surfaceflinger/tests/vsync/vsync.cpp b/services/surfaceflinger/tests/vsync/vsync.cpp
index a1b45e6..667dfb9 100644
--- a/services/surfaceflinger/tests/vsync/vsync.cpp
+++ b/services/surfaceflinger/tests/vsync/vsync.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <android/looper.h>
#include <gui/DisplayEventReceiver.h>
#include <utils/Looper.h>
@@ -82,3 +86,6 @@
return 0;
}
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"