Merge "Dumpsys sensorservice --proto"
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index a20db24..312db67 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -155,6 +155,8 @@
#define WLUTIL "/vendor/xbin/wlutil"
#define WMTRACE_DATA_DIR "/data/misc/wmtrace"
#define OTA_METADATA_DIR "/metadata/ota"
+#define SNAPSHOTCTL_LOG_DIR "/data/misc/snapshotctl_log"
+#define LINKERCONFIG_DIR "/linkerconfig"
// TODO(narayan): Since this information has to be kept in sync
// with tombstoned, we should just put it in a common header.
@@ -1532,6 +1534,9 @@
// This differs from the usual dumpsys stats, which is the stats report data.
RunDumpsys("STATSDSTATS", {"stats", "--metadata"});
+ // Add linker configuration directory
+ ds.AddDir(LINKERCONFIG_DIR, true);
+
RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(DumpIncidentReport);
return Dumpstate::RunStatus::OK;
@@ -1563,6 +1568,7 @@
ds.AddDir(RECOVERY_DATA_DIR, true);
ds.AddDir(UPDATE_ENGINE_LOG_DIR, true);
ds.AddDir(LOGPERSIST_DATA_DIR, false);
+ ds.AddDir(SNAPSHOTCTL_LOG_DIR, false);
if (!PropertiesHelper::IsUserBuild()) {
ds.AddDir(PROFILE_DATA_DIR_CUR, true);
ds.AddDir(PROFILE_DATA_DIR_REF, true);
diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp
index d398559..3a3df08 100644
--- a/cmds/flatland/GLHelper.cpp
+++ b/cmds/flatland/GLHelper.cpp
@@ -14,15 +14,14 @@
* limitations under the License.
*/
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-
-#include <ui/DisplayInfo.h>
-#include <gui/SurfaceComposerClient.h>
-
#include "GLHelper.h"
- namespace android {
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <gui/SurfaceComposerClient.h>
+#include <ui/DisplayConfig.h>
+
+namespace android {
GLHelper::GLHelper() :
mDisplay(EGL_NO_DISPLAY),
@@ -228,15 +227,15 @@
return false;
}
- DisplayInfo info;
- status_t err = mSurfaceComposerClient->getDisplayInfo(dpy, &info);
+ DisplayConfig config;
+ status_t err = mSurfaceComposerClient->getActiveDisplayConfig(dpy, &config);
if (err != NO_ERROR) {
- fprintf(stderr, "SurfaceComposer::getDisplayInfo failed: %#x\n", err);
+ fprintf(stderr, "SurfaceComposer::getActiveDisplayConfig failed: %#x\n", err);
return false;
}
- float scaleX = float(info.w) / float(w);
- float scaleY = float(info.h) / float(h);
+ float scaleX = static_cast<float>(config.resolution.getWidth()) / w;
+ float scaleY = static_cast<float>(config.resolution.getHeight()) / h;
*scale = scaleX < scaleY ? scaleX : scaleY;
return true;
diff --git a/cmds/installd/TEST_MAPPING b/cmds/installd/TEST_MAPPING
index 287f2d9..c6583a1 100644
--- a/cmds/installd/TEST_MAPPING
+++ b/cmds/installd/TEST_MAPPING
@@ -15,6 +15,10 @@
{
"name": "installd_utils_test"
},
+ // AdoptableHostTest moves packages, part of which is handled by installd
+ {
+ "name": "AdoptableHostTest"
+ },
{
"name": "CtsUsesLibraryHostTestCases"
},
diff --git a/include/android/imagedecoder.h b/include/android/imagedecoder.h
index 0d943b7..6e5da52 100644
--- a/include/android/imagedecoder.h
+++ b/include/android/imagedecoder.h
@@ -15,12 +15,24 @@
*/
/**
- * @addtogroup ImageDecoder
+ * @defgroup ImageDecoder
+ *
+ * Functions for converting encoded images into RGBA pixels.
+ *
+ * Similar to the Java counterpart android.graphics.ImageDecoder, it can be used
+ * to decode images like PNG, JPEG, GIF, WEBP and HEIF. It has similar options
+ * for scaling, cropping, and choosing the output format. Unlike the Java API,
+ * which can create an android.graphics.Bitmap or
+ * android.graphics.drawable.Drawable object, AImageDecoder decodes directly
+ * into memory provided by the client. For more information, see the
+ * <a href="https://developer.android.com/ndk/guides/image-decoder">Image decoder</a>
+ * developer guide.
* @{
*/
/**
- * @file imageDecoder.h
+ * @file imagedecoder.h
+ * @brief API for decoding images.
*/
#ifndef ANDROID_IMAGE_DECODER_H
@@ -38,32 +50,54 @@
#if __ANDROID_API__ >= 30
-/** AImageDecoder functions result code. */
+/**
+ * {@link AImageDecoder} functions result code. Many functions will return one of these
+ * to indicate success ({@link ANDROID_IMAGE_DECODER_SUCCESS}) or the reason
+ * for the failure. On failure, any out-parameters should be considered
+ * uninitialized, except where specified.
+ */
enum {
- // Decoding was successful and complete.
+ /**
+ * Decoding was successful and complete.
+ */
ANDROID_IMAGE_DECODER_SUCCESS = 0,
- // The input was incomplete. In decodeImage, this means a partial
- // image was decoded. Undecoded lines are all zeroes.
- // In AImageDecoder_create*, no AImageDecoder was created.
+ /**
+ * The input was incomplete.
+ */
ANDROID_IMAGE_DECODER_INCOMPLETE = -1,
- // The input contained an error after decoding some lines. Similar to
- // INCOMPLETE, above.
+ /**
+ * The input contained an error after decoding some lines.
+ */
ANDROID_IMAGE_DECODER_ERROR = -2,
- // Could not convert, e.g. attempting to decode an image with
- // alpha to an opaque format.
+ /**
+ * Could not convert. For example, attempting to decode an image with
+ * alpha to an opaque format.
+ */
ANDROID_IMAGE_DECODER_INVALID_CONVERSION = -3,
- // The scale is invalid. It may have overflowed, or it may be incompatible
- // with the current alpha setting.
+ /**
+ * The scale is invalid. It may have overflowed, or it may be incompatible
+ * with the current alpha setting.
+ */
ANDROID_IMAGE_DECODER_INVALID_SCALE = -4,
- // Some other parameter was bad (e.g. pixels)
+ /**
+ * Some other parameter was bad.
+ */
ANDROID_IMAGE_DECODER_BAD_PARAMETER = -5,
- // Input was invalid i.e. broken before decoding any pixels.
+ /**
+ * Input was invalid before decoding any pixels.
+ */
ANDROID_IMAGE_DECODER_INVALID_INPUT = -6,
- // A seek was required, and failed.
+ /**
+ * A seek was required and it failed.
+ */
ANDROID_IMAGE_DECODER_SEEK_ERROR = -7,
- // Some other error (e.g. OOM)
+ /**
+ * Some other error. For example, an internal allocation failed.
+ */
ANDROID_IMAGE_DECODER_INTERNAL_ERROR = -8,
- // We did not recognize the format
+ /**
+ * AImageDecoder did not recognize the format.
+ */
ANDROID_IMAGE_DECODER_UNSUPPORTED_FORMAT = -9
};
@@ -76,36 +110,45 @@
* - {@link AImageDecoder_createFromAAsset}
* - {@link AImageDecoder_createFromFd}
* - {@link AImageDecoder_createFromBuffer}
+ *
+ * After creation, {@link AImageDecoder_getHeaderInfo} can be used to retrieve
+ * information about the encoded image. Other functions, like
+ * {@link AImageDecoder_setTargetSize}, can be used to specify how to decode, and
+ * {@link AImageDecoder_decode} will decode into client provided memory.
+ *
+ * {@link AImageDecoder} objects are NOT thread-safe, and should not be shared across
+ * threads.
*/
typedef struct AImageDecoder AImageDecoder;
/**
- * Create a new AImageDecoder from an AAsset.
+ * Create a new {@link AImageDecoder} from an {@link AAsset}.
*
* @param asset {@link AAsset} containing encoded image data. Client is still
- * responsible for calling {@link AAsset_close} on it.
+ * responsible for calling {@link AAsset_close} on it, which may be
+ * done after deleting the returned {@link AImageDecoder}.
* @param outDecoder On success (i.e. return value is
* {@link ANDROID_IMAGE_DECODER_SUCCESS}), this will be set to
* a newly created {@link AImageDecoder}. Caller is
* responsible for calling {@link AImageDecoder_delete} on it.
* @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
- * indicating reason for the failure.
+ * indicating the reason for the failure.
*/
int AImageDecoder_createFromAAsset(struct AAsset* asset, AImageDecoder** outDecoder)
__INTRODUCED_IN(30);
/**
- * Create a new AImageDecoder from a file descriptor.
+ * Create a new {@link AImageDecoder} from a file descriptor.
*
* @param fd Seekable, readable, open file descriptor for encoded data.
* Client is still responsible for closing it, which may be done
- * *after* deleting the returned AImageDecoder.
+ * after deleting the returned {@link AImageDecoder}.
* @param outDecoder On success (i.e. return value is
* {@link ANDROID_IMAGE_DECODER_SUCCESS}), this will be set to
* a newly created {@link AImageDecoder}. Caller is
* responsible for calling {@link AImageDecoder_delete} on it.
* @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
- * indicating reason for the failure.
+ * indicating the reason for the failure.
*/
int AImageDecoder_createFromFd(int fd, AImageDecoder** outDecoder) __INTRODUCED_IN(30);
@@ -113,7 +156,7 @@
* Create a new AImageDecoder from a buffer.
*
* @param buffer Pointer to encoded data. Must be valid for the entire time
- * the AImageDecoder is used.
+ * the {@link AImageDecoder} is used.
* @param length Byte length of buffer.
* @param outDecoder On success (i.e. return value is
* {@link ANDROID_IMAGE_DECODER_SUCCESS}), this will be set to
@@ -136,7 +179,7 @@
* @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
+ * otherwise. In the latter case, the {@link AImageDecoder} uses the
* format it was already planning to use (either its default
* or a previously successful setting from this function).
*/
@@ -146,23 +189,25 @@
/**
* Specify whether the output's pixels should be unpremultiplied.
*
- * 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
+ * By default, {@link AImageDecoder_decodeImage} will premultiply the pixels, if they have alpha.
+ * Pass true to this method to leave them unpremultiplied. This has no effect on an
* opaque image.
*
- * @param required Pass true to leave the pixels unpremultiplied.
- * @return - {@link ANDROID_IMAGE_DECODER_SUCCESS} on success
+ * @param unpremultipliedRequired Pass true to leave the pixels unpremultiplied.
+ * @return an enum describing whether the call succeeded.
+ * - {@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_setUnpremultipliedRequired(AImageDecoder*, bool required) __INTRODUCED_IN(30);
+int AImageDecoder_setUnpremultipliedRequired(AImageDecoder*,
+ bool unpremultipliedRequired) __INTRODUCED_IN(30);
/**
* Choose the dataspace for the output.
*
- * Not supported for {@link ANDROID_BITMAP_FORMAT_A_8}, which does not support
- * an ADataSpace.
+ * Ignored by {@link ANDROID_BITMAP_FORMAT_A_8}, which does not support
+ * an {@link ADataSpace}.
*
* @param dataspace The {@link ADataSpace} to decode into. An ADataSpace
* specifies how to interpret the colors. By default,
@@ -170,10 +215,10 @@
* {@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.
+ * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or
+ * {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER} for a null
+ * {@link AImageDecoder} or an integer that does not correspond to an
+ * {@link ADataSpace} value.
*/
int AImageDecoder_setDataSpace(AImageDecoder*, int32_t dataspace) __INTRODUCED_IN(30);
@@ -191,10 +236,11 @@
* {@link AImageDecoder_getMinimumStride}, which will now return
* a value based on this width.
* @param height Height of the output (prior to cropping).
- * @return - {@link ANDROID_IMAGE_DECODER_SUCCESS} on success
- * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER} if the AImageDecoder
- * pointer is null, width or height is <= 0, or any existing crop is
- * not contained by the image dimensions.
+ * @return an enum describing whether the call succeeded.
+ * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or
+ * {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER} if the {@link AImageDecoder}
+ * pointer is null, width or height is <= 0, or any existing crop is
+ * not contained by the new image dimensions.
*/
int AImageDecoder_setTargetSize(AImageDecoder*, int32_t width, int32_t height) __INTRODUCED_IN(30);
@@ -213,10 +259,11 @@
* 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.
+ * in the 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.
+ * in the direction that the decoder can do most efficiently.
+ * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or
+ * {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER} for bad input.
*/
int AImageDecoder_computeSampledSize(const AImageDecoder*, int sampleSize,
int32_t* width, int32_t* height) __INTRODUCED_IN(30);
@@ -234,18 +281,21 @@
* value based on the width of the crop. An empty ARect -
* specifically { 0, 0, 0, 0 } - may be used to remove the cropping
* behavior. Any other empty or unsorted ARects will result in
- * returning ANDROID_IMAGE_DECODER_BAD_PARAMETER.
- * @return - {@link ANDROID_IMAGE_DECODER_SUCCESS} on success
- * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER} if the AImageDecoder
- * pointer is null or the crop is not contained by the image
- * dimensions.
+ * returning {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}.
+ * @return an enum describing whether the call succeeded.
+ * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or
+ * {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER} if the {@link AImageDecoder}
+ * pointer is null or the crop is not contained by the image
+ * dimensions.
*/
int AImageDecoder_setCrop(AImageDecoder*, ARect crop) __INTRODUCED_IN(30);
-/**
- * Opaque handle for reading header info.
- */
struct AImageDecoderHeaderInfo;
+/**
+ * Opaque handle for representing information about the encoded image. It can
+ * be passed to methods like {@link AImageDecoderHeaderInfo_getWidth} and
+ * {@link AImageDecoderHeaderInfo_getHeight}.
+ */
typedef struct AImageDecoderHeaderInfo AImageDecoderHeaderInfo;
/**
@@ -258,12 +308,16 @@
const AImageDecoder*) __INTRODUCED_IN(30);
/**
- * Report the native width of the encoded image.
+ * Report the native width of the encoded image. This is also the logical
+ * pixel width of the output, unless {@link AImageDecoder_setTargetSize} is
+ * used to choose a different size.
*/
int32_t AImageDecoderHeaderInfo_getWidth(const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
/**
- * Report the native height of the encoded image.
+ * Report the native height of the encoded image. This is also the logical
+ * pixel height of the output, unless {@link AImageDecoder_setTargetSize} is
+ * used to choose a different size.
*/
int32_t AImageDecoderHeaderInfo_getHeight(const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
@@ -277,7 +331,7 @@
/**
* Report the {@link AndroidBitmapFormat} the AImageDecoder will decode to
- * by default. AImageDecoder will try to choose one that is sensible
+ * by default. {@link 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.
*/
@@ -285,18 +339,17 @@
const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
/**
- * Report how the AImageDecoder will handle alpha by default. If the image
+ * Report how the {@link AImageDecoder} will handle alpha by default. If the image
* contains no alpha (according to its header), this will return
* {@link ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE}. If the image may contain alpha,
- * this returns {@link ANDROID_BITMAP_FLAGS_ALPHA_PREMUL}.
- *
- * For animated images only the opacity of the first frame is reported.
+ * this returns {@link ANDROID_BITMAP_FLAGS_ALPHA_PREMUL}, because
+ * {@link AImageDecoder_decodeImage} will premultiply pixels by default.
*/
int AImageDecoderHeaderInfo_getAlphaFlags(
const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
/**
- * Report the dataspace the AImageDecoder will decode to by default.
+ * Report the dataspace the {@link 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.
@@ -315,26 +368,35 @@
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.
+ * Return the minimum stride that can be used in
+ * {@link AImageDecoder_decodeImage).
+ *
+ * This stride provides no padding, meaning it will be exactly equal to the
+ * width times the number of bytes per pixel for the {@link AndroidBitmapFormat}
+ * being used.
+ *
+ * If the output is scaled (via {@link AImageDecoder_setTargetSize}) and/or
+ * cropped (via {@link AImageDecoder_setCrop}), this takes those into account.
*/
size_t AImageDecoder_getMinimumStride(AImageDecoder*) __INTRODUCED_IN(30);
/**
- * Decode the image into pixels, using the settings of the AImageDecoder.
+ * Decode the image into pixels, using the settings of the {@link AImageDecoder}.
*
* @param decoder Opaque object representing the decoder.
* @param pixels On success, will be filled with the result
- * of the decode. Must be large enough to fit |size| bytes.
+ * of the decode. Must be large enough to hold |size| bytes.
* @param stride Width in bytes of a single row. Must be at least
- * {@link AImageDecoder_getMinimumStride}.
+ * {@link AImageDecoder_getMinimumStride} and a multiple of the
+ * bytes per pixel of the {@link AndroidBitmapFormat}.
* @param size Size of the pixel buffer in bytes. Must be at least
* stride * (height - 1) +
- * {@link AImageDecoder_getMinimumStride}. Must also be a multiple
- * of the bytes per pixel of the {@link AndroidBitmapFormat}.
+ * {@link AImageDecoder_getMinimumStride}.
* @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success, or an error code
* from the same enum describing the failure.
+ * {@link ANDROID_IMAGE_DECODER_INCOMPLETE} or
+ * {@link ANDROID_IMAGE_DECODER_ERROR} means that a partial image was
+ * decoded, and undecoded lines have been initialized to all zeroes.
*/
int AImageDecoder_decodeImage(AImageDecoder* decoder,
void* pixels, size_t stride,
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 079dd82..1ee3853 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -73,7 +73,6 @@
// or dessert updates. Instead, apex users should use libbinder_ndk.
apex_available: [
"//apex_available:platform",
- "com.android.vndk.current",
// TODO(b/139016109) remove these three
"com.android.media.swcodec",
"test_com.android.media.swcodec",
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 994e3b9..9f8d752 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -507,7 +507,7 @@
}
}
-#if defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || (defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__))
+#if defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
constexpr int32_t kHeader = B_PACK_CHARS('V', 'N', 'D', 'R');
#else
constexpr int32_t kHeader = B_PACK_CHARS('S', 'Y', 'S', 'T');
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 37c0d77..bdc2e40 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -60,14 +60,14 @@
: mIsMain(isMain)
{
}
-
+
protected:
virtual bool threadLoop()
{
IPCThreadState::self()->joinThreadPool(mIsMain);
return false;
}
-
+
const bool mIsMain;
};
@@ -296,7 +296,7 @@
void ProcessState::expungeHandle(int32_t handle, IBinder* binder)
{
AutoMutex _l(mLock);
-
+
handle_entry* e = lookupHandleLocked(handle);
// This handle may have already been replaced with a new BpBinder
@@ -387,7 +387,7 @@
{
// TODO(b/139016109): enforce in build system
-#if defined(__ANDROID_APEX__) && !defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__)
+#if defined(__ANDROID_APEX__)
LOG_ALWAYS_FATAL("Cannot use libbinder in APEX (only system.img libbinder) since it is not stable.");
#endif
@@ -418,5 +418,5 @@
}
mDriverFD = -1;
}
-
+
} // namespace android
diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
index a7a7292..618f88c 100644
--- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
+++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
@@ -87,4 +87,7 @@
* package.
*/
@utf8InCpp String getModuleMetadataPackageName();
+
+ /* Returns the names of all packages. */
+ @utf8InCpp String[] getAllPackages();
}
diff --git a/libs/binder/include/binder/Stability.h b/libs/binder/include/binder/Stability.h
index b2f51d3..2894482 100644
--- a/libs/binder/include/binder/Stability.h
+++ b/libs/binder/include/binder/Stability.h
@@ -81,7 +81,7 @@
VINTF = 0b111111,
};
-#if defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || (defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__))
+#if defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
static constexpr Level kLocalStability = Level::VENDOR;
#else
static constexpr Level kLocalStability = Level::SYSTEM;
diff --git a/libs/binder/ndk/include_platform/android/binder_stability.h b/libs/binder/ndk/include_platform/android/binder_stability.h
index 56d95a7..f5e8bf6 100644
--- a/libs/binder/ndk/include_platform/android/binder_stability.h
+++ b/libs/binder/ndk/include_platform/android/binder_stability.h
@@ -30,8 +30,7 @@
FLAG_PRIVATE_VENDOR = 0x10000000,
};
-#if defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || \
- (defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__))
+#if defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
enum {
FLAG_PRIVATE_LOCAL = FLAG_PRIVATE_VENDOR,
@@ -46,8 +45,7 @@
AIBinder_markVendorStability(binder);
}
-#else // defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || (defined(__ANDROID_VNDK__) &&
- // !defined(__ANDROID_APEX__))
+#else // defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
enum {
FLAG_PRIVATE_LOCAL = 0,
@@ -64,8 +62,7 @@
AIBinder_markSystemStability(binder);
}
-#endif // defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || (defined(__ANDROID_VNDK__) &&
- // !defined(__ANDROID_APEX__))
+#endif // defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
/**
* This interface has system<->vendor stability
diff --git a/libs/bufferqueueconverter/Android.bp b/libs/bufferqueueconverter/Android.bp
new file mode 100644
index 0000000..bab2674
--- /dev/null
+++ b/libs/bufferqueueconverter/Android.bp
@@ -0,0 +1,28 @@
+cc_library_headers {
+ name: "libbufferqueueconverter_headers",
+ vendor_available: true,
+ export_include_dirs: ["include"],
+}
+
+cc_library_shared {
+ name: "libbufferqueueconverter",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ double_loadable: true,
+
+ srcs: [
+ "BufferQueueConverter.cpp",
+ ],
+
+ shared_libs: [
+ "libgui",
+ "libui",
+ "libutils",
+ "libbinder",
+ "libbase",
+ "liblog",
+ ],
+ export_include_dirs: ["include"],
+}
diff --git a/libs/bufferqueueconverter/BufferQueueConverter.cpp b/libs/bufferqueueconverter/BufferQueueConverter.cpp
new file mode 100644
index 0000000..b1896fa
--- /dev/null
+++ b/libs/bufferqueueconverter/BufferQueueConverter.cpp
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+#include <gui/Surface.h>
+#include <gui/bufferqueue/2.0/H2BGraphicBufferProducer.h>
+
+#include "include/bufferqueueconverter/BufferQueueConverter.h"
+
+
+using ::android::Surface;
+using ::android::IGraphicBufferProducer;
+using ::android::hardware::graphics::bufferqueue::V2_0::utils::H2BGraphicBufferProducer;
+
+
+namespace android {
+
+struct SurfaceHolder {
+ sp<Surface> surface;
+ SurfaceHolder(const sp<Surface>& s) : surface(s) {}
+};
+
+/**
+ * Custom deleter for SurfaceHolder unique pointer
+ */
+void destroySurfaceHolder(SurfaceHolder* surfaceHolder) {
+ delete surfaceHolder;
+}
+
+
+SurfaceHolderUniquePtr getSurfaceFromHGBP(const sp<HGraphicBufferProducer>& token) {
+ if (token == nullptr) {
+ ALOGE("Passed IGraphicBufferProducer handle is invalid.");
+ return SurfaceHolderUniquePtr(nullptr, nullptr);
+ }
+
+ sp<IGraphicBufferProducer> bufferProducer = new H2BGraphicBufferProducer(token);
+ if (bufferProducer == nullptr) {
+ ALOGE("Failed to get IGraphicBufferProducer.");
+ return SurfaceHolderUniquePtr(nullptr, nullptr);
+ }
+
+ sp<Surface> newSurface(new Surface(bufferProducer, true));
+ if (newSurface == nullptr) {
+ ALOGE("Failed to create Surface from HGBP.");
+ return SurfaceHolderUniquePtr(nullptr, nullptr);
+ }
+
+ return SurfaceHolderUniquePtr(new SurfaceHolder(newSurface), destroySurfaceHolder);
+}
+
+
+ANativeWindow* getNativeWindow(SurfaceHolder* handle) {
+ if (handle == nullptr) {
+ ALOGE("SurfaceHolder is invalid.");
+ return nullptr;
+ }
+
+ return static_cast<ANativeWindow*>(handle->surface.get());
+}
+
+} // namespace android
diff --git a/libs/bufferqueueconverter/include/bufferqueueconverter/BufferQueueConverter.h b/libs/bufferqueueconverter/include/bufferqueueconverter/BufferQueueConverter.h
new file mode 100644
index 0000000..84bceba
--- /dev/null
+++ b/libs/bufferqueueconverter/include/bufferqueueconverter/BufferQueueConverter.h
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_BUFFER_QUEUE_CONVERTER_H
+#define ANDROID_BUFFER_QUEUE_CONVERTER_H
+
+#include <gui/IGraphicBufferProducer.h>
+#include <android/native_window.h>
+
+using ::android::sp;
+using HGraphicBufferProducer =
+ ::android::hardware::graphics::bufferqueue::V2_0::IGraphicBufferProducer;
+
+namespace android {
+ /**
+ * Opaque handle for a data structure holding Surface.
+ */
+ typedef struct SurfaceHolder SurfaceHolder;
+
+ /**
+ * SurfaceHolder unique pointer type
+ */
+ using SurfaceHolderUniquePtr = std::unique_ptr<SurfaceHolder, void(*)(SurfaceHolder*)>;
+
+ /**
+ * Returns a SurfaceHolder that wraps a Surface generated from a given HGBP.
+ *
+ * @param token Hardware IGraphicBufferProducer to create a
+ * Surface.
+ * @return SurfaceHolder Unique pointer to created SurfaceHolder object.
+ */
+ SurfaceHolderUniquePtr getSurfaceFromHGBP(const sp<HGraphicBufferProducer>& token);
+
+ /**
+ * Returns ANativeWindow pointer from a given SurfaceHolder. Returned
+ * pointer is valid only while the containing SurfaceHolder is alive.
+ *
+ * @param surfaceHolder SurfaceHolder to generate a native window.
+ * @return ANativeWindow* a pointer to a generated native window.
+ */
+ ANativeWindow* getNativeWindow(SurfaceHolder* surfaceHolder);
+
+} // namespace android
+
+#endif // ANDROID_BUFFER_QUEUE_CONVERTER_H
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 4e62da7..e2f5d31 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -31,6 +31,68 @@
namespace android {
+void BLASTBufferItemConsumer::onDisconnect() {
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+ mPreviouslyConnected = mCurrentlyConnected;
+ mCurrentlyConnected = false;
+ if (mPreviouslyConnected) {
+ mDisconnectEvents.push(mCurrentFrameNumber);
+ }
+ mFrameEventHistory.onDisconnect();
+}
+
+void BLASTBufferItemConsumer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
+ FrameEventHistoryDelta* outDelta) {
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+ if (newTimestamps) {
+ // BufferQueueProducer only adds a new timestamp on
+ // queueBuffer
+ mCurrentFrameNumber = newTimestamps->frameNumber;
+ mFrameEventHistory.addQueue(*newTimestamps);
+ }
+ if (outDelta) {
+ // frame event histories will be processed
+ // only after the producer connects and requests
+ // deltas for the first time. Forward this intent
+ // to SF-side to turn event processing back on
+ mPreviouslyConnected = mCurrentlyConnected;
+ mCurrentlyConnected = true;
+ mFrameEventHistory.getAndResetDelta(outDelta);
+ }
+}
+
+void BLASTBufferItemConsumer::updateFrameTimestamps(uint64_t frameNumber, nsecs_t refreshStartTime,
+ const sp<Fence>& glDoneFence,
+ const sp<Fence>& presentFence,
+ const sp<Fence>& prevReleaseFence,
+ CompositorTiming compositorTiming,
+ nsecs_t latchTime, nsecs_t dequeueReadyTime) {
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+
+ // if the producer is not connected, don't bother updating,
+ // the next producer that connects won't access this frame event
+ if (!mCurrentlyConnected) return;
+ std::shared_ptr<FenceTime> glDoneFenceTime = std::make_shared<FenceTime>(glDoneFence);
+ std::shared_ptr<FenceTime> presentFenceTime = std::make_shared<FenceTime>(presentFence);
+ std::shared_ptr<FenceTime> releaseFenceTime = std::make_shared<FenceTime>(prevReleaseFence);
+
+ mFrameEventHistory.addLatch(frameNumber, latchTime);
+ mFrameEventHistory.addRelease(frameNumber, dequeueReadyTime, std::move(releaseFenceTime));
+ mFrameEventHistory.addPreComposition(frameNumber, refreshStartTime);
+ mFrameEventHistory.addPostComposition(frameNumber, glDoneFenceTime, presentFenceTime,
+ compositorTiming);
+}
+
+void BLASTBufferItemConsumer::getConnectionEvents(uint64_t frameNumber, bool* needsDisconnect) {
+ bool disconnect = false;
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+ while (!mDisconnectEvents.empty() && mDisconnectEvents.front() <= frameNumber) {
+ disconnect = true;
+ mDisconnectEvents.pop();
+ }
+ if (needsDisconnect != nullptr) *needsDisconnect = disconnect;
+}
+
BLASTBufferQueue::BLASTBufferQueue(const sp<SurfaceControl>& surface, int width, int height)
: mSurfaceControl(surface),
mWidth(width),
@@ -39,7 +101,7 @@
BufferQueue::createBufferQueue(&mProducer, &mConsumer);
mConsumer->setMaxAcquiredBufferCount(MAX_ACQUIRED_BUFFERS);
mBufferItemConsumer =
- new BufferItemConsumer(mConsumer, AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER, 1, true);
+ new BLASTBufferItemConsumer(mConsumer, AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER, 1, true);
static int32_t id = 0;
auto name = std::string("BLAST Consumer") + std::to_string(id);
id++;
@@ -79,11 +141,21 @@
std::unique_lock _lock{mMutex};
ATRACE_CALL();
+ if (!stats.empty()) {
+ mTransformHint = stats[0].transformHint;
+ mBufferItemConsumer->setTransformHint(mTransformHint);
+ mBufferItemConsumer->updateFrameTimestamps(stats[0].frameEventStats.frameNumber,
+ stats[0].frameEventStats.refreshStartTime,
+ stats[0].frameEventStats.gpuCompositionDoneFence,
+ stats[0].presentFence,
+ stats[0].previousReleaseFence,
+ stats[0].frameEventStats.compositorTiming,
+ stats[0].latchTime,
+ stats[0].frameEventStats.dequeueReadyTime);
+ }
if (mPendingReleaseItem.item.mGraphicBuffer != nullptr) {
- if (stats.size() > 0) {
+ if (!stats.empty()) {
mPendingReleaseItem.releaseFence = stats[0].previousReleaseFence;
- mTransformHint = stats[0].transformHint;
- mBufferItemConsumer->setTransformHint(mTransformHint);
} else {
ALOGE("Warning: no SurfaceControlStats returned in BLASTBufferQueue callback");
mPendingReleaseItem.releaseFence = nullptr;
@@ -144,6 +216,14 @@
mNumAcquired++;
mSubmitted.push(bufferItem);
+ bool needsDisconnect = false;
+ mBufferItemConsumer->getConnectionEvents(bufferItem.mFrameNumber, &needsDisconnect);
+
+ // if producer disconnected before, notify SurfaceFlinger
+ if (needsDisconnect) {
+ t->notifyProducerDisconnect(mSurfaceControl);
+ }
+
// Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback.
incStrong((void*)transactionCallbackThunk);
diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp
index c04d907..6749c3c 100644
--- a/libs/gui/FrameTimestamps.cpp
+++ b/libs/gui/FrameTimestamps.cpp
@@ -355,6 +355,10 @@
mProducerWantsEvents = false;
}
+void ConsumerFrameEventHistory::setProducerWantsEvents() {
+ mProducerWantsEvents = true;
+}
+
void ConsumerFrameEventHistory::initializeCompositorTiming(
const CompositorTiming& compositorTiming) {
mCompositorTiming = compositorTiming;
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 073543c..2f27fd2 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -34,8 +34,10 @@
#include <system/graphics.h>
+#include <ui/DisplayConfig.h>
#include <ui/DisplayInfo.h>
#include <ui/DisplayStatInfo.h>
+#include <ui/DisplayState.h>
#include <ui/HdrCapabilities.h>
#include <utils/Log.h>
@@ -351,22 +353,43 @@
remote()->transact(BnSurfaceComposer::SET_POWER_MODE, data, &reply);
}
- virtual status_t getDisplayConfigs(const sp<IBinder>& display,
- Vector<DisplayInfo>* configs)
- {
+ virtual status_t getDisplayState(const sp<IBinder>& display, ui::DisplayState* state) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ data.writeStrongBinder(display);
+ remote()->transact(BnSurfaceComposer::GET_DISPLAY_STATE, data, &reply);
+ const status_t result = reply.readInt32();
+ if (result == NO_ERROR) {
+ memcpy(state, reply.readInplace(sizeof(ui::DisplayState)), sizeof(ui::DisplayState));
+ }
+ return result;
+ }
+
+ virtual status_t getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ data.writeStrongBinder(display);
+ remote()->transact(BnSurfaceComposer::GET_DISPLAY_INFO, data, &reply);
+ const status_t result = reply.readInt32();
+ if (result == NO_ERROR) {
+ memcpy(info, reply.readInplace(sizeof(DisplayInfo)), sizeof(DisplayInfo));
+ }
+ return result;
+ }
+
+ virtual status_t getDisplayConfigs(const sp<IBinder>& display, Vector<DisplayConfig>* configs) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
data.writeStrongBinder(display);
remote()->transact(BnSurfaceComposer::GET_DISPLAY_CONFIGS, data, &reply);
- status_t result = reply.readInt32();
+ const status_t result = reply.readInt32();
if (result == NO_ERROR) {
- size_t numConfigs = reply.readUint32();
+ const size_t numConfigs = reply.readUint32();
configs->clear();
configs->resize(numConfigs);
for (size_t c = 0; c < numConfigs; ++c) {
- memcpy(&(configs->editItemAt(c)),
- reply.readInplace(sizeof(DisplayInfo)),
- sizeof(DisplayInfo));
+ memcpy(&(configs->editItemAt(c)), reply.readInplace(sizeof(DisplayConfig)),
+ sizeof(DisplayConfig));
}
}
return result;
@@ -1297,17 +1320,40 @@
reply->writeStrongBinder(display);
return NO_ERROR;
}
+ case GET_DISPLAY_STATE: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ ui::DisplayState state;
+ const sp<IBinder> display = data.readStrongBinder();
+ const status_t result = getDisplayState(display, &state);
+ reply->writeInt32(result);
+ if (result == NO_ERROR) {
+ memcpy(reply->writeInplace(sizeof(ui::DisplayState)), &state,
+ sizeof(ui::DisplayState));
+ }
+ return NO_ERROR;
+ }
+ case GET_DISPLAY_INFO: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ DisplayInfo info;
+ const sp<IBinder> display = data.readStrongBinder();
+ const status_t result = getDisplayInfo(display, &info);
+ reply->writeInt32(result);
+ if (result == NO_ERROR) {
+ memcpy(reply->writeInplace(sizeof(DisplayInfo)), &info, sizeof(DisplayInfo));
+ }
+ return NO_ERROR;
+ }
case GET_DISPLAY_CONFIGS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
- Vector<DisplayInfo> configs;
- sp<IBinder> display = data.readStrongBinder();
- status_t result = getDisplayConfigs(display, &configs);
+ Vector<DisplayConfig> configs;
+ const sp<IBinder> display = data.readStrongBinder();
+ const status_t result = getDisplayConfigs(display, &configs);
reply->writeInt32(result);
if (result == NO_ERROR) {
reply->writeUint32(static_cast<uint32_t>(configs.size()));
for (size_t c = 0; c < configs.size(); ++c) {
- memcpy(reply->writeInplace(sizeof(DisplayInfo)),
- &configs[c], sizeof(DisplayInfo));
+ memcpy(reply->writeInplace(sizeof(DisplayConfig)), &configs[c],
+ sizeof(DisplayConfig));
}
}
return NO_ERROR;
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index e5e25aa..69f7894 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -30,6 +30,66 @@
} // Anonymous namespace
+status_t FrameEventHistoryStats::writeToParcel(Parcel* output) const {
+ status_t err = output->writeUint64(frameNumber);
+ if (err != NO_ERROR) return err;
+
+ if (gpuCompositionDoneFence) {
+ err = output->writeBool(true);
+ if (err != NO_ERROR) return err;
+
+ err = output->write(*gpuCompositionDoneFence);
+ } else {
+ err = output->writeBool(false);
+ }
+ if (err != NO_ERROR) return err;
+
+ err = output->writeInt64(compositorTiming.deadline);
+ if (err != NO_ERROR) return err;
+
+ err = output->writeInt64(compositorTiming.interval);
+ if (err != NO_ERROR) return err;
+
+ err = output->writeInt64(compositorTiming.presentLatency);
+ if (err != NO_ERROR) return err;
+
+ err = output->writeInt64(refreshStartTime);
+ if (err != NO_ERROR) return err;
+
+ err = output->writeInt64(dequeueReadyTime);
+ return err;
+}
+
+status_t FrameEventHistoryStats::readFromParcel(const Parcel* input) {
+ status_t err = input->readUint64(&frameNumber);
+ if (err != NO_ERROR) return err;
+
+ bool hasFence = false;
+ err = input->readBool(&hasFence);
+ if (err != NO_ERROR) return err;
+
+ if (hasFence) {
+ gpuCompositionDoneFence = new Fence();
+ err = input->read(*gpuCompositionDoneFence);
+ if (err != NO_ERROR) return err;
+ }
+
+ err = input->readInt64(&(compositorTiming.deadline));
+ if (err != NO_ERROR) return err;
+
+ err = input->readInt64(&(compositorTiming.interval));
+ if (err != NO_ERROR) return err;
+
+ err = input->readInt64(&(compositorTiming.presentLatency));
+ if (err != NO_ERROR) return err;
+
+ err = input->readInt64(&refreshStartTime);
+ if (err != NO_ERROR) return err;
+
+ err = input->readInt64(&dequeueReadyTime);
+ return err;
+}
+
status_t SurfaceStats::writeToParcel(Parcel* output) const {
status_t err = output->writeStrongBinder(surfaceControl);
if (err != NO_ERROR) {
@@ -49,6 +109,11 @@
err = output->writeBool(false);
}
err = output->writeUint32(transformHint);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ err = output->writeParcelable(eventStats);
return err;
}
@@ -74,6 +139,11 @@
}
}
err = input->readUint32(&transformHint);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ err = input->readParcelable(&eventStats);
return err;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 63dc333..7017b7c 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -31,8 +31,6 @@
#include <system/graphics.h>
-#include <ui/DisplayInfo.h>
-
#include <gui/BufferItemConsumer.h>
#include <gui/CpuConsumer.h>
#include <gui/IGraphicBufferProducer.h>
@@ -41,6 +39,7 @@
#include <gui/LayerState.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
+#include <ui/DisplayConfig.h>
#ifndef NO_INPUT
#include <input/InputWindow.h>
@@ -223,8 +222,10 @@
surfaceControlStats
.emplace_back(callbacksMap[callbackId]
.surfaceControls[surfaceStats.surfaceControl],
- surfaceStats.acquireTime, surfaceStats.previousReleaseFence,
- surfaceStats.transformHint);
+ transactionStats.latchTime, surfaceStats.acquireTime,
+ transactionStats.presentFence,
+ surfaceStats.previousReleaseFence, surfaceStats.transformHint,
+ surfaceStats.eventStats);
if (callbacksMap[callbackId].surfaceControls[surfaceStats.surfaceControl]) {
callbacksMap[callbackId]
.surfaceControls[surfaceStats.surfaceControl]
@@ -1236,6 +1237,18 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::notifyProducerDisconnect(
+ const sp<SurfaceControl>& sc) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+
+ s->what |= layer_state_t::eProducerDisconnect;
+ return *this;
+}
+
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::detachChildren(
const sp<SurfaceControl>& sc) {
layer_state_t* s = getLayerState(sc);
@@ -1623,15 +1636,23 @@
return sf->injectVSync(when);
}
-status_t SurfaceComposerClient::getDisplayConfigs(
- const sp<IBinder>& display, Vector<DisplayInfo>* configs)
-{
+status_t SurfaceComposerClient::getDisplayState(const sp<IBinder>& display,
+ ui::DisplayState* state) {
+ return ComposerService::getComposerService()->getDisplayState(display, state);
+}
+
+status_t SurfaceComposerClient::getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info) {
+ return ComposerService::getComposerService()->getDisplayInfo(display, info);
+}
+
+status_t SurfaceComposerClient::getDisplayConfigs(const sp<IBinder>& display,
+ Vector<DisplayConfig>* configs) {
return ComposerService::getComposerService()->getDisplayConfigs(display, configs);
}
-status_t SurfaceComposerClient::getDisplayInfo(const sp<IBinder>& display,
- DisplayInfo* info) {
- Vector<DisplayInfo> configs;
+status_t SurfaceComposerClient::getActiveDisplayConfig(const sp<IBinder>& display,
+ DisplayConfig* config) {
+ Vector<DisplayConfig> configs;
status_t result = getDisplayConfigs(display, &configs);
if (result != NO_ERROR) {
return result;
@@ -1643,7 +1664,7 @@
return NAME_NOT_FOUND;
}
- *info = configs[static_cast<size_t>(activeId)];
+ *config = configs[static_cast<size_t>(activeId)];
return NO_ERROR;
}
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index be429fe..d72eb5a 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -33,6 +33,35 @@
class BufferItemConsumer;
+class BLASTBufferItemConsumer : public BufferItemConsumer {
+public:
+ BLASTBufferItemConsumer(const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage,
+ int bufferCount, bool controlledByApp)
+ : BufferItemConsumer(consumer, consumerUsage, bufferCount, controlledByApp),
+ mCurrentlyConnected(false),
+ mPreviouslyConnected(false) {}
+
+ void onDisconnect() override;
+ void addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
+ FrameEventHistoryDelta* outDelta) override
+ REQUIRES(mFrameEventHistoryMutex);
+ void updateFrameTimestamps(uint64_t frameNumber, nsecs_t refreshStartTime,
+ const sp<Fence>& gpuCompositionDoneFence,
+ const sp<Fence>& presentFence, const sp<Fence>& prevReleaseFence,
+ CompositorTiming compositorTiming, nsecs_t latchTime,
+ nsecs_t dequeueReadyTime) REQUIRES(mFrameEventHistoryMutex);
+ void getConnectionEvents(uint64_t frameNumber, bool* needsDisconnect);
+
+private:
+ uint64_t mCurrentFrameNumber = 0;
+
+ Mutex mFrameEventHistoryMutex;
+ ConsumerFrameEventHistory mFrameEventHistory GUARDED_BY(mFrameEventHistoryMutex);
+ std::queue<uint64_t> mDisconnectEvents GUARDED_BY(mFrameEventHistoryMutex);
+ bool mCurrentlyConnected GUARDED_BY(mFrameEventHistoryMutex);
+ bool mPreviouslyConnected GUARDED_BY(mFrameEventHistoryMutex);
+};
+
class BLASTBufferQueue
: public ConsumerBase::FrameAvailableListener, public BufferItemConsumer::BufferFreedListener
{
@@ -89,7 +118,7 @@
sp<IGraphicBufferConsumer> mConsumer;
sp<IGraphicBufferProducer> mProducer;
- sp<BufferItemConsumer> mBufferItemConsumer;
+ sp<BLASTBufferItemConsumer> mBufferItemConsumer;
SurfaceComposerClient::Transaction* mNextTransaction GUARDED_BY(mMutex);
};
diff --git a/libs/gui/include/gui/FrameTimestamps.h b/libs/gui/include/gui/FrameTimestamps.h
index df02494..4af8659 100644
--- a/libs/gui/include/gui/FrameTimestamps.h
+++ b/libs/gui/include/gui/FrameTimestamps.h
@@ -174,7 +174,6 @@
std::shared_ptr<FenceTime> acquireFence{FenceTime::NO_FENCE};
};
-
// Used by the consumer to keep track of which fields it already sent to
// the producer.
class FrameEventDirtyFields {
@@ -207,6 +206,7 @@
~ConsumerFrameEventHistory() override;
void onDisconnect();
+ void setProducerWantsEvents();
void initializeCompositorTiming(const CompositorTiming& compositorTiming);
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 46c9f3a..e860f61 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_GUI_ISURFACE_COMPOSER_H
-#define ANDROID_GUI_ISURFACE_COMPOSER_H
+#pragma once
#include <stdint.h>
#include <sys/types.h>
@@ -46,13 +45,13 @@
#include <vector>
namespace android {
-// ----------------------------------------------------------------------------
struct client_cache_t;
struct ComposerState;
-struct DisplayState;
+struct DisplayConfig;
struct DisplayInfo;
struct DisplayStatInfo;
+struct DisplayState;
struct InputWindowCommands;
class LayerDebugInfo;
class HdrCapabilities;
@@ -63,6 +62,12 @@
class Rect;
enum class FrameEvent;
+namespace ui {
+
+struct DisplayState;
+
+} // namespace ui
+
/*
* This class defines the Binder IPC interface for accessing various
* SurfaceFlinger features.
@@ -161,10 +166,6 @@
*/
virtual void setPowerMode(const sp<IBinder>& display, int mode) = 0;
- /* returns information for each configuration of the given display
- * intended to be used to get information about built-in displays */
- virtual status_t getDisplayConfigs(const sp<IBinder>& display,
- Vector<DisplayInfo>* configs) = 0;
/* returns display statistics for a given display
* intended to be used by the media framework to properly schedule
@@ -172,8 +173,25 @@
virtual status_t getDisplayStats(const sp<IBinder>& display,
DisplayStatInfo* stats) = 0;
- /* indicates which of the configurations returned by getDisplayInfo is
- * currently active */
+ /**
+ * Get transactional state of given display.
+ */
+ virtual status_t getDisplayState(const sp<IBinder>& display, ui::DisplayState*) = 0;
+
+ /**
+ * Get immutable information about given physical display.
+ */
+ virtual status_t getDisplayInfo(const sp<IBinder>& display, DisplayInfo*) = 0;
+
+ /**
+ * Get configurations supported by given physical display.
+ */
+ virtual status_t getDisplayConfigs(const sp<IBinder>& display, Vector<DisplayConfig>*) = 0;
+
+ /**
+ * Get the index into configurations returned by getDisplayConfigs,
+ * corresponding to the active configuration.
+ */
virtual int getActiveConfig(const sp<IBinder>& display) = 0;
virtual status_t getDisplayColorModes(const sp<IBinder>& display,
@@ -493,7 +511,7 @@
// Java by ActivityManagerService.
BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
CREATE_CONNECTION,
- CREATE_GRAPHIC_BUFFER_ALLOC_UNUSED, // unused, fails permissions check
+ GET_DISPLAY_INFO,
CREATE_DISPLAY_EVENT_CONNECTION,
CREATE_DISPLAY,
DESTROY_DISPLAY,
@@ -503,7 +521,7 @@
GET_SUPPORTED_FRAME_TIMESTAMPS,
GET_DISPLAY_CONFIGS,
GET_ACTIVE_CONFIG,
- CONNECT_DISPLAY_UNUSED, // unused, fails permissions check
+ GET_DISPLAY_STATE,
CAPTURE_SCREEN,
CAPTURE_LAYERS,
CLEAR_ANIMATION_FRAME_STATS,
@@ -546,8 +564,4 @@
Parcel* reply, uint32_t flags = 0);
};
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_GUI_ISURFACE_COMPOSER_H
+} // namespace android
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
index 9c15225..c58634b 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -21,6 +21,7 @@
#include <binder/Parcelable.h>
#include <binder/SafeInterface.h>
+#include <gui/FrameTimestamps.h>
#include <ui/Fence.h>
#include <utils/Timers.h>
@@ -35,6 +36,27 @@
using CallbackId = int64_t;
+class FrameEventHistoryStats : public Parcelable {
+public:
+ status_t writeToParcel(Parcel* output) const override;
+ status_t readFromParcel(const Parcel* input) override;
+
+ FrameEventHistoryStats() = default;
+ FrameEventHistoryStats(uint64_t fn, const sp<Fence>& gpuCompFence, CompositorTiming compTiming,
+ nsecs_t refreshTime, nsecs_t dequeueReadyTime)
+ : frameNumber(fn),
+ gpuCompositionDoneFence(gpuCompFence),
+ compositorTiming(compTiming),
+ refreshStartTime(refreshTime),
+ dequeueReadyTime(dequeueReadyTime) {}
+
+ uint64_t frameNumber;
+ sp<Fence> gpuCompositionDoneFence;
+ CompositorTiming compositorTiming;
+ nsecs_t refreshStartTime;
+ nsecs_t dequeueReadyTime;
+};
+
class SurfaceStats : public Parcelable {
public:
status_t writeToParcel(Parcel* output) const override;
@@ -42,16 +64,18 @@
SurfaceStats() = default;
SurfaceStats(const sp<IBinder>& sc, nsecs_t time, const sp<Fence>& prevReleaseFence,
- uint32_t hint)
+ uint32_t hint, FrameEventHistoryStats frameEventStats)
: surfaceControl(sc),
acquireTime(time),
previousReleaseFence(prevReleaseFence),
- transformHint(hint) {}
+ transformHint(hint),
+ eventStats(frameEventStats) {}
sp<IBinder> surfaceControl;
nsecs_t acquireTime = -1;
sp<Fence> previousReleaseFence;
uint32_t transformHint = 0;
+ FrameEventHistoryStats eventStats;
};
class TransactionStats : public Parcelable {
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index c256a09..2d53b48 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -102,6 +102,7 @@
eFrameRateSelectionPriority = 0x20'00000000,
eFrameRateChanged = 0x40'00000000,
eBackgroundBlurRadiusChanged = 0x80'00000000,
+ eProducerDisconnect = 0x100'00000000,
};
layer_state_t()
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 08e6a5a..d0bb6a3 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_GUI_SURFACE_COMPOSER_CLIENT_H
-#define ANDROID_GUI_SURFACE_COMPOSER_CLIENT_H
+#pragma once
#include <stdint.h>
#include <sys/types.h>
@@ -46,29 +45,31 @@
namespace android {
-// ---------------------------------------------------------------------------
-
-struct DisplayInfo;
class HdrCapabilities;
class ISurfaceComposerClient;
class IGraphicBufferProducer;
class IRegionSamplingListener;
class Region;
-// ---------------------------------------------------------------------------
-
struct SurfaceControlStats {
- SurfaceControlStats(const sp<SurfaceControl>& sc, nsecs_t time,
- const sp<Fence>& prevReleaseFence, uint32_t hint)
+ SurfaceControlStats(const sp<SurfaceControl>& sc, nsecs_t latchTime, nsecs_t acquireTime,
+ const sp<Fence>& presentFence, const sp<Fence>& prevReleaseFence,
+ uint32_t hint, FrameEventHistoryStats eventStats)
: surfaceControl(sc),
- acquireTime(time),
+ latchTime(latchTime),
+ acquireTime(acquireTime),
+ presentFence(presentFence),
previousReleaseFence(prevReleaseFence),
- transformHint(hint) {}
+ transformHint(hint),
+ frameEventStats(eventStats) {}
sp<SurfaceControl> surfaceControl;
+ nsecs_t latchTime = -1;
nsecs_t acquireTime = -1;
+ sp<Fence> presentFence;
sp<Fence> previousReleaseFence;
uint32_t transformHint = 0;
+ FrameEventHistoryStats frameEventStats;
};
using TransactionCompletedCallbackTakesContext =
@@ -102,18 +103,21 @@
status_t linkToComposerDeath(const sp<IBinder::DeathRecipient>& recipient,
void* cookie = nullptr, uint32_t flags = 0);
- // Get a list of supported configurations for a given display
- static status_t getDisplayConfigs(const sp<IBinder>& display,
- Vector<DisplayInfo>* configs);
+ // Get transactional state of given display.
+ static status_t getDisplayState(const sp<IBinder>& display, ui::DisplayState*);
- // Get the DisplayInfo for the currently-active configuration
- static status_t getDisplayInfo(const sp<IBinder>& display,
- DisplayInfo* info);
+ // Get immutable information about given physical display.
+ static status_t getDisplayInfo(const sp<IBinder>& display, DisplayInfo*);
- // Get the index of the current active configuration (relative to the list
- // returned by getDisplayInfo)
+ // Get configurations supported by given physical display.
+ static status_t getDisplayConfigs(const sp<IBinder>& display, Vector<DisplayConfig>*);
+
+ // Get the ID of the active DisplayConfig, as getDisplayConfigs index.
static int getActiveConfig(const sp<IBinder>& display);
+ // Shorthand for getDisplayConfigs element at getActiveConfig index.
+ static status_t getActiveDisplayConfig(const sp<IBinder>& display, DisplayConfig*);
+
// 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().
@@ -487,6 +491,9 @@
Transaction& addTransactionCompletedCallback(
TransactionCompletedCallbackTakesContext callback, void* callbackContext);
+ // ONLY FOR BLAST ADAPTER
+ Transaction& notifyProducerDisconnect(const sp<SurfaceControl>& sc);
+
// Detaches all child surfaces (and their children recursively)
// from their SurfaceControl.
// The child SurfaceControls will not throw exceptions or return errors,
@@ -644,8 +651,4 @@
void onTransactionCompleted(ListenerStats stats) override;
};
-// ---------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_GUI_SURFACE_COMPOSER_CLIENT_H
+} // namespace android
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 41f0d40..b40eb14 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -21,11 +21,12 @@
#include <android/hardware/graphics/common/1.2/types.h>
#include <gui/BufferQueueCore.h>
#include <gui/BufferQueueProducer.h>
+#include <gui/FrameTimestamps.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/IProducerListener.h>
#include <gui/SurfaceComposerClient.h>
#include <private/gui/ComposerService.h>
-#include <ui/DisplayInfo.h>
+#include <ui/DisplayConfig.h>
#include <ui/GraphicBuffer.h>
#include <ui/GraphicTypes.h>
#include <ui/Transform.h>
@@ -103,10 +104,11 @@
t.apply();
t.clear();
- DisplayInfo info;
- ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(mDisplayToken, &info));
- mDisplayWidth = info.w;
- mDisplayHeight = info.h;
+ DisplayConfig config;
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(mDisplayToken, &config));
+ const ui::Size& resolution = config.resolution;
+ mDisplayWidth = resolution.getWidth();
+ mDisplayHeight = resolution.getHeight();
mSurfaceControl = mClient->createSurface(String8("TestSurface"), mDisplayWidth,
mDisplayHeight, PIXEL_FORMAT_RGBA_8888,
@@ -114,7 +116,7 @@
/*parent*/ nullptr);
t.setLayerStack(mSurfaceControl, 0)
.setLayer(mSurfaceControl, std::numeric_limits<int32_t>::max())
- .setFrame(mSurfaceControl, Rect(0, 0, mDisplayWidth, mDisplayHeight))
+ .setFrame(mSurfaceControl, Rect(resolution))
.show(mSurfaceControl)
.setDataspace(mSurfaceControl, ui::Dataspace::V0_SRGB)
.apply();
@@ -646,4 +648,79 @@
TEST_F(BLASTBufferQueueTransformTest, setTransform_ROT_270) {
test(ui::Transform::ROT_270);
}
+
+class BLASTFrameEventHistoryTest : public BLASTBufferQueueTest {
+public:
+ void setUpAndQueueBuffer(const sp<IGraphicBufferProducer>& igbProducer,
+ nsecs_t* requestedPresentTime, nsecs_t* postedTime,
+ IGraphicBufferProducer::QueueBufferOutput* qbOutput,
+ bool getFrameTimestamps) {
+ int slot;
+ sp<Fence> fence;
+ sp<GraphicBuffer> buf;
+ auto ret = igbProducer->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight,
+ PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN,
+ nullptr, nullptr);
+ ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret);
+ ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf));
+
+ nsecs_t requestedTime = systemTime();
+ if (requestedPresentTime) *requestedPresentTime = requestedTime;
+ IGraphicBufferProducer::QueueBufferInput input(requestedTime, false, HAL_DATASPACE_UNKNOWN,
+ Rect(mDisplayWidth, mDisplayHeight),
+ NATIVE_WINDOW_SCALING_MODE_FREEZE, 0,
+ Fence::NO_FENCE, /*sticky*/ 0,
+ getFrameTimestamps);
+ if (postedTime) *postedTime = systemTime();
+ igbProducer->queueBuffer(slot, input, qbOutput);
+ }
+};
+
+TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_Basic) {
+ BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+ sp<IGraphicBufferProducer> igbProducer;
+ ProducerFrameEventHistory history;
+ setUpProducer(adapter, igbProducer);
+
+ IGraphicBufferProducer::QueueBufferOutput qbOutput;
+ nsecs_t requestedPresentTimeA = 0;
+ nsecs_t postedTimeA = 0;
+ setUpAndQueueBuffer(igbProducer, &requestedPresentTimeA, &postedTimeA, &qbOutput, true);
+ history.applyDelta(qbOutput.frameTimestamps);
+
+ FrameEvents* events = nullptr;
+ events = history.getFrame(1);
+ ASSERT_NE(nullptr, events);
+ ASSERT_EQ(1, events->frameNumber);
+ ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime);
+ ASSERT_GE(events->postedTime, postedTimeA);
+
+ adapter.waitForCallbacks();
+
+ // queue another buffer so we query for frame event deltas
+ nsecs_t requestedPresentTimeB = 0;
+ nsecs_t postedTimeB = 0;
+ setUpAndQueueBuffer(igbProducer, &requestedPresentTimeB, &postedTimeB, &qbOutput, true);
+ history.applyDelta(qbOutput.frameTimestamps);
+ events = history.getFrame(1);
+ ASSERT_NE(nullptr, events);
+
+ // frame number, requestedPresentTime, and postTime should not have changed
+ ASSERT_EQ(1, events->frameNumber);
+ ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime);
+ ASSERT_GE(events->postedTime, postedTimeA);
+
+ ASSERT_GE(events->latchTime, postedTimeA);
+ ASSERT_GE(events->dequeueReadyTime, events->latchTime);
+ ASSERT_NE(nullptr, events->gpuCompositionDoneFence);
+ ASSERT_NE(nullptr, events->displayPresentFence);
+ ASSERT_NE(nullptr, events->releaseFence);
+
+ // we should also have gotten the initial values for the next frame
+ events = history.getFrame(2);
+ ASSERT_NE(nullptr, events);
+ ASSERT_EQ(2, events->frameNumber);
+ ASSERT_EQ(requestedPresentTimeB, events->requestedPresentTime);
+ ASSERT_GE(events->postedTime, postedTimeB);
+}
} // namespace android
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 04749e6..1a623e2 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -41,7 +41,7 @@
#include <input/InputTransport.h>
#include <input/Input.h>
-#include <ui/DisplayInfo.h>
+#include <ui/DisplayConfig.h>
#include <ui/Rect.h>
#include <ui/Region.h>
@@ -223,13 +223,13 @@
const auto display = mComposerClient->getInternalDisplayToken();
ASSERT_NE(display, nullptr);
- DisplayInfo info;
- ASSERT_EQ(NO_ERROR, mComposerClient->getDisplayInfo(display, &info));
+ DisplayConfig config;
+ ASSERT_EQ(NO_ERROR, mComposerClient->getActiveDisplayConfig(display, &config));
// After a new buffer is queued, SurfaceFlinger is notified and will
// latch the new buffer on next vsync. Let's heuristically wait for 3
// vsyncs.
- mBufferPostDelay = int32_t(1e6 / info.fps) * 3;
+ mBufferPostDelay = static_cast<int32_t>(1e6 / config.refreshRate) * 3;
}
void TearDown() {
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 25c032f..70fd888 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -718,8 +718,15 @@
}
void setPowerMode(const sp<IBinder>& /*display*/, int /*mode*/) override {}
- status_t getDisplayConfigs(const sp<IBinder>& /*display*/,
- Vector<DisplayInfo>* /*configs*/) override { return NO_ERROR; }
+ status_t getDisplayInfo(const sp<IBinder>& /*display*/, DisplayInfo*) override {
+ return NO_ERROR;
+ }
+ status_t getDisplayConfigs(const sp<IBinder>& /*display*/, Vector<DisplayConfig>*) override {
+ return NO_ERROR;
+ }
+ status_t getDisplayState(const sp<IBinder>& /*display*/, ui::DisplayState*) override {
+ return NO_ERROR;
+ }
status_t getDisplayStats(const sp<IBinder>& /*display*/,
DisplayStatInfo* /*stats*/) override { return NO_ERROR; }
int getActiveConfig(const sp<IBinder>& /*display*/) override { return 0; }
diff --git a/libs/nativedisplay/ADisplay.cpp b/libs/nativedisplay/ADisplay.cpp
index 1e25049..277635c 100644
--- a/libs/nativedisplay/ADisplay.cpp
+++ b/libs/nativedisplay/ADisplay.cpp
@@ -16,6 +16,7 @@
#include <apex/display.h>
#include <gui/SurfaceComposerClient.h>
+#include <ui/DisplayConfig.h>
#include <ui/DisplayInfo.h>
#include <ui/GraphicTypes.h>
#include <ui/PixelFormat.h>
@@ -116,17 +117,12 @@
LOG_ALWAYS_FATAL_IF(name == nullptr, "nullptr passed as " #name " argument");
namespace {
+
sp<IBinder> getToken(ADisplay* display) {
DisplayImpl* impl = reinterpret_cast<DisplayImpl*>(display);
return SurfaceComposerClient::getPhysicalDisplayToken(impl->id);
}
-int64_t computeSfOffset(const DisplayInfo& info) {
- // This should probably be part of the config instead of extrapolated from
- // the presentation deadline and fudged here, but the way the math works out
- // here we do get the right offset.
- return static_cast<int64_t>((1000000000 / info.fps) - info.presentationDeadline + 1000000);
-}
} // namespace
namespace android {
@@ -142,9 +138,16 @@
int numConfigs = 0;
for (int i = 0; i < size; ++i) {
const sp<IBinder> token = SurfaceComposerClient::getPhysicalDisplayToken(ids[i]);
- Vector<DisplayInfo> configs;
- const status_t status = SurfaceComposerClient::getDisplayConfigs(token, &configs);
- if (status != OK) {
+
+ DisplayInfo info;
+ if (const status_t status = SurfaceComposerClient::getDisplayInfo(token, &info);
+ status != OK) {
+ return status;
+ }
+
+ Vector<DisplayConfig> configs;
+ if (const status_t status = SurfaceComposerClient::getDisplayConfigs(token, &configs);
+ status != OK) {
return status;
}
if (configs.empty()) {
@@ -154,11 +157,11 @@
numConfigs += configs.size();
configsPerDisplay[i].reserve(configs.size());
for (int j = 0; j < configs.size(); ++j) {
- const DisplayInfo config = configs[j];
+ const DisplayConfig& config = configs[j];
configsPerDisplay[i].emplace_back(
- DisplayConfigImpl{static_cast<int32_t>(config.w),
- static_cast<int32_t>(config.h), config.density, config.fps,
- computeSfOffset(config), config.appVsyncOffset});
+ DisplayConfigImpl{config.resolution.getWidth(), config.resolution.getHeight(),
+ info.density, config.refreshRate, config.sfVsyncOffset,
+ config.appVsyncOffset});
}
}
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index 2caffca..a1c9eb8 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -331,3 +331,7 @@
void ANativeWindow_allocateBuffers(ANativeWindow* window) {
window->perform(window, NATIVE_WINDOW_ALLOCATE_BUFFERS);
}
+
+int64_t ANativeWindow_getNextFrameId(ANativeWindow* window) {
+ return query64(window, NATIVE_WINDOW_GET_NEXT_FRAME_ID);
+}
diff --git a/libs/nativewindow/include/apex/window.h b/libs/nativewindow/include/apex/window.h
index 3dec011..02b886c 100644
--- a/libs/nativewindow/include/apex/window.h
+++ b/libs/nativewindow/include/apex/window.h
@@ -212,4 +212,11 @@
*/
void ANativeWindow_allocateBuffers(ANativeWindow* window);
+/**
+ * Retrieves an identifier for the next frame to be queued by this window.
+ *
+ * \return -errno on error, otherwise returns the next frame id.
+ */
+int64_t ANativeWindow_getNextFrameId(ANativeWindow* window);
+
__END_DECLS
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index 427f317..e0e20c3 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -26,6 +26,7 @@
ANativeWindow_getLastDequeueDuration; # apex # introduced=30
ANativeWindow_getLastDequeueStartTime; # apex # introduced=30
ANativeWindow_getLastQueueDuration; # apex # introduced=30
+ ANativeWindow_getNextFrameId; # apex # introduced=30
ANativeWindow_getWidth;
ANativeWindow_lock;
ANativeWindow_query; # llndk
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index 2e3ab4c..4c7b629 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -52,6 +52,7 @@
"gl/GLExtensions.cpp",
"gl/GLFramebuffer.cpp",
"gl/GLImage.cpp",
+ "gl/GLShadowTexture.cpp",
"gl/GLShadowVertexGenerator.cpp",
"gl/GLSkiaShadowPort.cpp",
"gl/ImageManager.cpp",
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 98605ba..69003fb 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -1661,6 +1661,7 @@
mState.cornerRadius = 0.0f;
mState.drawShadows = true;
+ setupLayerTexturing(mShadowTexture.getTexture());
drawMesh(mesh);
mState.drawShadows = false;
}
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 45c85de..4fc457f 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -32,6 +32,7 @@
#include <renderengine/RenderEngine.h>
#include <renderengine/private/Description.h>
#include <sys/types.h>
+#include "GLShadowTexture.h"
#include "ImageManager.h"
#define EGL_NO_CONFIG ((EGLConfig)0)
@@ -183,6 +184,7 @@
GLuint mVpWidth;
GLuint mVpHeight;
Description mState;
+ GLShadowTexture mShadowTexture;
mat4 mSrgbToXyz;
mat4 mDisplayP3ToXyz;
diff --git a/libs/renderengine/gl/GLShadowTexture.cpp b/libs/renderengine/gl/GLShadowTexture.cpp
new file mode 100644
index 0000000..2423a34
--- /dev/null
+++ b/libs/renderengine/gl/GLShadowTexture.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES3/gl3.h>
+
+#include "GLShadowTexture.h"
+#include "GLSkiaShadowPort.h"
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+GLShadowTexture::GLShadowTexture() {
+ fillShadowTextureData(mTextureData, SHADOW_TEXTURE_WIDTH);
+
+ glGenTextures(1, &mName);
+ glBindTexture(GL_TEXTURE_2D, mName);
+ glTexImage2D(GL_TEXTURE_2D, 0 /* base image level */, GL_ALPHA, SHADOW_TEXTURE_WIDTH,
+ SHADOW_TEXTURE_HEIGHT, 0 /* border */, GL_ALPHA, GL_UNSIGNED_BYTE, mTextureData);
+ mTexture.init(Texture::TEXTURE_2D, mName);
+ mTexture.setFiltering(true);
+ mTexture.setDimensions(SHADOW_TEXTURE_WIDTH, 1);
+}
+
+GLShadowTexture::~GLShadowTexture() {
+ glDeleteTextures(1, &mName);
+}
+
+const Texture& GLShadowTexture::getTexture() {
+ return mTexture;
+}
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/gl/GLShadowTexture.h b/libs/renderengine/gl/GLShadowTexture.h
new file mode 100644
index 0000000..250a9d7
--- /dev/null
+++ b/libs/renderengine/gl/GLShadowTexture.h
@@ -0,0 +1,44 @@
+/*
+ * 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 <renderengine/Texture.h>
+#include <cstdint>
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+class GLShadowTexture {
+public:
+ GLShadowTexture();
+ ~GLShadowTexture();
+
+ const Texture& getTexture();
+
+private:
+ static constexpr int SHADOW_TEXTURE_WIDTH = 128;
+ static constexpr int SHADOW_TEXTURE_HEIGHT = 1;
+
+ GLuint mName;
+ Texture mTexture;
+ uint8_t mTextureData[SHADOW_TEXTURE_WIDTH];
+};
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/gl/GLSkiaShadowPort.cpp b/libs/renderengine/gl/GLSkiaShadowPort.cpp
index 224ce6c..da8b435 100644
--- a/libs/renderengine/gl/GLSkiaShadowPort.cpp
+++ b/libs/renderengine/gl/GLSkiaShadowPort.cpp
@@ -644,6 +644,13 @@
2.0f * devSpaceSpotBlur, std::abs(insetWidth));
}
+void fillShadowTextureData(uint8_t* data, size_t shadowTextureWidth) {
+ for (int i = 0; i < shadowTextureWidth; i++) {
+ const float d = 1 - i / ((shadowTextureWidth * 1.0f) - 1.0f);
+ data[i] = static_cast<uint8_t>((exp(-4.0f * d * d) - 0.018f) * 255);
+ }
+}
+
} // namespace gl
} // namespace renderengine
} // namespace android
diff --git a/libs/renderengine/gl/GLSkiaShadowPort.h b/libs/renderengine/gl/GLSkiaShadowPort.h
index e7d1861..912c8bb 100644
--- a/libs/renderengine/gl/GLSkiaShadowPort.h
+++ b/libs/renderengine/gl/GLSkiaShadowPort.h
@@ -17,13 +17,11 @@
#pragma once
#include <math/vec4.h>
+#include <renderengine/Mesh.h>
#include <ui/Rect.h>
namespace android {
namespace renderengine {
-
-class Mesh;
-
namespace gl {
/**
@@ -79,6 +77,20 @@
void fillIndicesForGeometry(const Geometry& shadowGeometry, int indexCount,
int startingVertexOffset, uint16_t* indices);
+/**
+ * Maps shadow geometry 'alpha' varying (1 for darkest, 0 for transparent) to
+ * darkness at that spot. Values are determined by an exponential falloff
+ * function provided by UX.
+ *
+ * The texture is used for quick lookup in theshadow shader.
+ *
+ * textureData - filled with shadow texture data that needs to be at least of
+ * size textureWidth
+ *
+ * textureWidth - width of the texture, height is always 1
+ */
+void fillShadowTextureData(uint8_t* textureData, size_t textureWidth);
+
} // namespace gl
} // namespace renderengine
} // namespace android
diff --git a/libs/renderengine/gl/ProgramCache.cpp b/libs/renderengine/gl/ProgramCache.cpp
index ba0e4ad..3ae35ec 100644
--- a/libs/renderengine/gl/ProgramCache.cpp
+++ b/libs/renderengine/gl/ProgramCache.cpp
@@ -550,7 +550,7 @@
String8 ProgramCache::generateVertexShader(const Key& needs) {
Formatter vs;
- if (needs.isTexturing()) {
+ if (needs.hasTextureCoords()) {
vs << "attribute vec4 texCoords;"
<< "varying vec2 outTexCoords;";
}
@@ -559,16 +559,16 @@
vs << "varying lowp vec2 outCropCoords;";
}
if (needs.drawShadows()) {
- vs << "attribute vec4 shadowColor;";
- vs << "varying vec4 outShadowColor;";
- vs << "attribute vec4 shadowParams;";
- vs << "varying vec3 outShadowParams;";
+ vs << "attribute lowp vec4 shadowColor;";
+ vs << "varying lowp vec4 outShadowColor;";
+ vs << "attribute lowp vec4 shadowParams;";
+ vs << "varying lowp vec3 outShadowParams;";
}
vs << "attribute vec4 position;"
<< "uniform mat4 projection;"
<< "uniform mat4 texture;"
<< "void main(void) {" << indent << "gl_Position = projection * position;";
- if (needs.isTexturing()) {
+ if (needs.hasTextureCoords()) {
vs << "outTexCoords = (texture * texCoords).st;";
}
if (needs.hasRoundedCorners()) {
@@ -592,11 +592,13 @@
fs << "precision mediump float;";
if (needs.getTextureTarget() == Key::TEXTURE_EXT) {
- fs << "uniform samplerExternalOES sampler;"
- << "varying vec2 outTexCoords;";
+ fs << "uniform samplerExternalOES sampler;";
} else if (needs.getTextureTarget() == Key::TEXTURE_2D) {
- fs << "uniform sampler2D sampler;"
- << "varying vec2 outTexCoords;";
+ fs << "uniform sampler2D sampler;";
+ }
+
+ if (needs.hasTextureCoords()) {
+ fs << "varying vec2 outTexCoords;";
}
if (needs.hasRoundedCorners()) {
@@ -625,19 +627,17 @@
if (needs.drawShadows()) {
fs << R"__SHADER__(
- varying vec4 outShadowColor;
- varying vec3 outShadowParams;
+ varying lowp vec4 outShadowColor;
+ varying lowp vec3 outShadowParams;
/**
* Returns the shadow color.
*/
vec4 getShadowColor()
{
- // exponential falloff function provided by UX
- float d = length(outShadowParams.xy);
- float distance = outShadowParams.z * (1.0 - d);
- float factor = 1.0 - clamp(distance, 0.0, 1.0);
- factor = exp(-factor * factor * 4.0) - 0.018;
+ lowp float d = length(outShadowParams.xy);
+ vec2 uv = vec2(outShadowParams.z * (1.0 - d), 0.5);
+ lowp float factor = texture2D(sampler, uv).a;
return outShadowColor * factor;
}
)__SHADER__";
diff --git a/libs/renderengine/gl/ProgramCache.h b/libs/renderengine/gl/ProgramCache.h
index c8b6da7..901e631 100644
--- a/libs/renderengine/gl/ProgramCache.h
+++ b/libs/renderengine/gl/ProgramCache.h
@@ -128,6 +128,7 @@
}
inline bool isTexturing() const { return (mKey & TEXTURE_MASK) != TEXTURE_OFF; }
+ inline bool hasTextureCoords() const { return isTexturing() && !drawShadows(); }
inline int getTextureTarget() const { return (mKey & TEXTURE_MASK); }
inline bool isPremultiplied() const { return (mKey & BLEND_MASK) == BLEND_PREMULT; }
inline bool isOpaque() const { return (mKey & OPACITY_MASK) == OPACITY_OPAQUE; }
diff --git a/libs/ui/include/ui/DisplayConfig.h b/libs/ui/include/ui/DisplayConfig.h
new file mode 100644
index 0000000..09b8211
--- /dev/null
+++ b/libs/ui/include/ui/DisplayConfig.h
@@ -0,0 +1,40 @@
+/*
+ * 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 <type_traits>
+
+#include <ui/Size.h>
+#include <utils/Timers.h>
+
+namespace android {
+
+// Configuration supported by physical display.
+struct DisplayConfig {
+ ui::Size resolution;
+ float xDpi = 0;
+ float yDpi = 0;
+
+ float refreshRate = 0;
+ nsecs_t appVsyncOffset = 0;
+ nsecs_t sfVsyncOffset = 0;
+ nsecs_t presentationDeadline = 0;
+};
+
+static_assert(std::is_trivially_copyable_v<DisplayConfig>);
+
+} // namespace android
diff --git a/libs/ui/include/ui/DisplayInfo.h b/libs/ui/include/ui/DisplayInfo.h
index 38f8d6b..7773319 100644
--- a/libs/ui/include/ui/DisplayInfo.h
+++ b/libs/ui/include/ui/DisplayInfo.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * 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.
@@ -14,35 +14,18 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_DISPLAY_INFO_H
-#define ANDROID_UI_DISPLAY_INFO_H
+#pragma once
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <ui/Rotation.h>
-#include <utils/Timers.h>
+#include <type_traits>
namespace android {
-constexpr uint32_t NO_LAYER_STACK = static_cast<uint32_t>(-1);
-
+// Immutable information about physical display.
struct DisplayInfo {
- uint32_t w{0};
- uint32_t h{0};
- float xdpi{0};
- float ydpi{0};
- float fps{0};
- float density{0};
- ui::Rotation orientation{ui::ROTATION_0};
- bool secure{false};
- nsecs_t appVsyncOffset{0};
- nsecs_t presentationDeadline{0};
- uint32_t viewportW{0};
- uint32_t viewportH{0};
- uint32_t layerStack{NO_LAYER_STACK};
+ float density = 0.f;
+ bool secure = false;
};
-} // namespace android
+static_assert(std::is_trivially_copyable_v<DisplayInfo>);
-#endif // ANDROID_COMPOSER_DISPLAY_INFO_H
+} // namespace android
diff --git a/libs/ui/include/ui/DisplayState.h b/libs/ui/include/ui/DisplayState.h
new file mode 100644
index 0000000..64efc84
--- /dev/null
+++ b/libs/ui/include/ui/DisplayState.h
@@ -0,0 +1,40 @@
+/*
+ * 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/Rotation.h>
+#include <ui/Size.h>
+
+#include <cstdint>
+#include <type_traits>
+
+namespace android::ui {
+
+using LayerStack = uint32_t;
+constexpr LayerStack NO_LAYER_STACK = static_cast<LayerStack>(-1);
+
+// Transactional state of physical or virtual display. Note that libgui defines
+// android::DisplayState as a superset of android::ui::DisplayState.
+struct DisplayState {
+ LayerStack layerStack = NO_LAYER_STACK;
+ Rotation orientation = ROTATION_0;
+ Size viewport;
+};
+
+static_assert(std::is_trivially_copyable_v<DisplayState>);
+
+} // namespace android::ui
diff --git a/libs/ui/include_vndk/ui/DisplayConfig.h b/libs/ui/include_vndk/ui/DisplayConfig.h
new file mode 120000
index 0000000..1450319
--- /dev/null
+++ b/libs/ui/include_vndk/ui/DisplayConfig.h
@@ -0,0 +1 @@
+../../include/ui/DisplayConfig.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/DisplayState.h b/libs/ui/include_vndk/ui/DisplayState.h
new file mode 120000
index 0000000..4e92849
--- /dev/null
+++ b/libs/ui/include_vndk/ui/DisplayState.h
@@ -0,0 +1 @@
+../../include/ui/DisplayState.h
\ No newline at end of file
diff --git a/opengl/tests/lib/WindowSurface.cpp b/opengl/tests/lib/WindowSurface.cpp
index 4dcc1ca..dfb9c92 100644
--- a/opengl/tests/lib/WindowSurface.cpp
+++ b/opengl/tests/lib/WindowSurface.cpp
@@ -16,10 +16,13 @@
#include <WindowSurface.h>
-#include <gui/SurfaceComposerClient.h>
+#include <utility>
+
#include <gui/ISurfaceComposer.h>
#include <gui/Surface.h>
-#include <ui/DisplayInfo.h>
+#include <gui/SurfaceComposerClient.h>
+#include <ui/DisplayConfig.h>
+#include <ui/DisplayState.h>
using namespace android;
@@ -33,28 +36,33 @@
return;
}
- // Get main display parameters.
- const auto mainDpy = SurfaceComposerClient::getInternalDisplayToken();
- if (mainDpy == nullptr) {
+ const auto displayToken = SurfaceComposerClient::getInternalDisplayToken();
+ if (displayToken == nullptr) {
fprintf(stderr, "ERROR: no display\n");
return;
}
- DisplayInfo mainDpyInfo;
- err = SurfaceComposerClient::getDisplayInfo(mainDpy, &mainDpyInfo);
+ DisplayConfig displayConfig;
+ err = SurfaceComposerClient::getActiveDisplayConfig(displayToken, &displayConfig);
if (err != NO_ERROR) {
- fprintf(stderr, "ERROR: unable to get display characteristics\n");
+ fprintf(stderr, "ERROR: unable to get active display config\n");
return;
}
- uint32_t width, height;
- if (mainDpyInfo.orientation != ui::ROTATION_0 && mainDpyInfo.orientation != ui::ROTATION_180) {
- // rotated
- width = mainDpyInfo.h;
- height = mainDpyInfo.w;
- } else {
- width = mainDpyInfo.w;
- height = mainDpyInfo.h;
+ ui::DisplayState displayState;
+ err = SurfaceComposerClient::getDisplayState(displayToken, &displayState);
+ if (err != NO_ERROR) {
+ fprintf(stderr, "ERROR: unable to get display state\n");
+ return;
+ }
+
+ const ui::Size& resolution = displayConfig.resolution;
+ auto width = resolution.getWidth();
+ auto height = resolution.getHeight();
+
+ if (displayState.orientation == ui::ROTATION_90 ||
+ displayState.orientation == ui::ROTATION_270) {
+ std::swap(width, height);
}
sp<SurfaceControl> sc = surfaceComposerClient->createSurface(
diff --git a/services/automotive/display/CarWindowService.cpp b/services/automotive/display/CarWindowService.cpp
index e95c9e1..09ae34a 100644
--- a/services/automotive/display/CarWindowService.cpp
+++ b/services/automotive/display/CarWindowService.cpp
@@ -13,7 +13,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-#include <ui/DisplayInfo.h>
+
+#include <utility>
+
#include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
#include "CarWindowService.h"
@@ -38,31 +40,35 @@
return nullptr;
}
- // Get main display parameters.
- sp<IBinder> mainDpy = SurfaceComposerClient::getInternalDisplayToken();
- if (mainDpy == nullptr) {
+ const auto displayToken = SurfaceComposerClient::getInternalDisplayToken();
+ if (displayToken == nullptr) {
ALOGE("Failed to get internal display ");
return nullptr;
}
- DisplayInfo mainDpyInfo;
- err = SurfaceComposerClient::getDisplayInfo(mainDpy, &mainDpyInfo);
+
+ err = SurfaceComposerClient::getActiveDisplayConfig(displayToken, &mDpyConfig);
if (err != NO_ERROR) {
- ALOGE("Failed to get display characteristics");
+ ALOGE("Failed to get active display config");
return nullptr;
}
- unsigned int mWidth, mHeight;
- if (mainDpyInfo.orientation != ui::ROTATION_0 &&
- mainDpyInfo.orientation != ui::ROTATION_180) {
- // rotated
- mWidth = mainDpyInfo.h;
- mHeight = mainDpyInfo.w;
- } else {
- mWidth = mainDpyInfo.w;
- mHeight = mainDpyInfo.h;
+
+ err = SurfaceComposerClient::getDisplayState(displayToken, &mDpyState);
+ if (err != NO_ERROR) {
+ ALOGE("Failed to get display state");
+ return nullptr;
+ }
+
+ const ui::Size& resolution = mDpyConfig.resolution;
+ auto width = resolution.getWidth();
+ auto height = resolution.getHeight();
+
+ if (mDpyState.orientation == ui::ROTATION_90 ||
+ mDpyState.orientation == ui::ROTATION_270) {
+ std::swap(width, height);
}
mSurfaceControl = mSurfaceComposerClient->createSurface(
- String8("Automotive Display"), mWidth, mHeight,
+ String8("Automotive Display"), width, height,
PIXEL_FORMAT_RGBX_8888, ISurfaceComposerClient::eOpaque);
if (mSurfaceControl == nullptr || !mSurfaceControl->isValid()) {
ALOGE("Failed to create SurfaceControl");
diff --git a/services/automotive/display/include/CarWindowService.h b/services/automotive/display/include/CarWindowService.h
index 3290cc7..a32ed7c 100644
--- a/services/automotive/display/include/CarWindowService.h
+++ b/services/automotive/display/include/CarWindowService.h
@@ -20,6 +20,8 @@
#include <gui/IGraphicBufferProducer.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
+#include <ui/DisplayConfig.h>
+#include <ui/DisplayState.h>
namespace android {
namespace frameworks {
@@ -37,11 +39,23 @@
Return<sp<IGraphicBufferProducer>> getIGraphicBufferProducer() override;
Return<bool> showWindow() override;
Return<bool> hideWindow() override;
+ Return<void> getDisplayInfo(getDisplayInfo_cb _info_cb) override {
+ HwDisplayConfig cfg;
+ cfg.setToExternal((uint8_t*)&mDpyConfig, sizeof(DisplayConfig));
+
+ HwDisplayState state;
+ state.setToExternal((uint8_t*)&mDpyState, sizeof(DisplayState));
+
+ _info_cb(cfg, state);
+ return hardware::Void();
+ }
private:
sp<android::Surface> mSurface;
sp<android::SurfaceComposerClient> mSurfaceComposerClient;
sp<android::SurfaceControl> mSurfaceControl;
+ DisplayConfig mDpyConfig;
+ ui::DisplayState mDpyState;
};
} // namespace implementation
} // namespace V1_0
diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp
index baba64f..6eed24a 100644
--- a/services/gpuservice/Android.bp
+++ b/services/gpuservice/Android.bp
@@ -20,6 +20,7 @@
"libbase",
"libbinder",
"libcutils",
+ "libgfxstats",
"libgraphicsenv",
"liblog",
"libutils",
@@ -52,7 +53,6 @@
name: "libgpuservice_sources",
srcs: [
"GpuService.cpp",
- "gpustats/GpuStats.cpp"
],
}
diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp
index be4a462..91a76f1 100644
--- a/services/gpuservice/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -24,14 +24,13 @@
#include <binder/Parcel.h>
#include <binder/PermissionCache.h>
#include <cutils/properties.h>
+#include <gpustats/GpuStats.h>
#include <private/android_filesystem_config.h>
#include <utils/String8.h>
#include <utils/Trace.h>
#include <vkjson.h>
-#include "gpustats/GpuStats.h"
-
namespace android {
using base::StringAppendF;
@@ -53,8 +52,9 @@
int64_t driverBuildTime, const std::string& appPackageName,
const int32_t vulkanVersion, GpuStatsInfo::Driver driver,
bool isDriverLoaded, int64_t driverLoadingTime) {
- mGpuStats->insert(driverPackageName, driverVersionName, driverVersionCode, driverBuildTime,
- appPackageName, vulkanVersion, driver, isDriverLoaded, driverLoadingTime);
+ mGpuStats->insertDriverStats(driverPackageName, driverVersionName, driverVersionCode,
+ driverBuildTime, appPackageName, vulkanVersion, driver,
+ isDriverLoaded, driverLoadingTime);
}
status_t GpuService::getGpuStatsGlobalInfo(std::vector<GpuStatsGlobalInfo>* outStats) const {
diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/GpuService.h
index b3dc2e2..525fb4f 100644
--- a/services/gpuservice/GpuService.h
+++ b/services/gpuservice/GpuService.h
@@ -25,22 +25,11 @@
#include <mutex>
#include <vector>
-#include <unordered_map>
namespace android {
class GpuStats;
-struct MemoryStruct {
- int64_t gpuMemory;
- int64_t mappedMemory;
- int64_t ionMemory;
-};
-
-// A map that keeps track of how much memory of each type is allocated by every process.
-// Format: map[pid][memoryType] = MemoryStruct()'
-using GpuMemoryMap = std::unordered_map<int32_t, std::unordered_map<std::string, MemoryStruct>>;
-
class GpuService : public BnGpuService, public PriorityDumper {
public:
static const char* const SERVICE_NAME ANDROID_API;
@@ -82,8 +71,6 @@
status_t doDump(int fd, const Vector<String16>& args, bool asProto);
- status_t getQCommGpuMemoryInfo(GpuMemoryMap* memories, std::string* result, int32_t dumpPid) const;
-
/*
* Attributes
*/
diff --git a/services/gpuservice/TEST_MAPPING b/services/gpuservice/TEST_MAPPING
new file mode 100644
index 0000000..b345355
--- /dev/null
+++ b/services/gpuservice/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "gpuservice_unittest"
+ }
+ ]
+}
diff --git a/services/gpuservice/gpustats/Android.bp b/services/gpuservice/gpustats/Android.bp
new file mode 100644
index 0000000..49a98cc
--- /dev/null
+++ b/services/gpuservice/gpustats/Android.bp
@@ -0,0 +1,21 @@
+cc_library_shared {
+ name: "libgfxstats",
+ srcs: [
+ "GpuStats.cpp",
+ ],
+ shared_libs: [
+ "libcutils",
+ "libgraphicsenv",
+ "liblog",
+ "libutils",
+ ],
+ export_include_dirs: ["include"],
+ cppflags: [
+ "-Wall",
+ "-Werror",
+ "-Wformat",
+ "-Wthread-safety",
+ "-Wunused",
+ "-Wunreachable-code",
+ ],
+}
diff --git a/services/gpuservice/gpustats/GpuStats.cpp b/services/gpuservice/gpustats/GpuStats.cpp
index 7fff6ed..71e6b97 100644
--- a/services/gpuservice/gpustats/GpuStats.cpp
+++ b/services/gpuservice/gpustats/GpuStats.cpp
@@ -17,7 +17,7 @@
#define LOG_TAG "GpuStats"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include "GpuStats.h"
+#include <gpustats/GpuStats.h>
#include <cutils/properties.h>
#include <log/log.h>
@@ -74,10 +74,11 @@
}
}
-void GpuStats::insert(const std::string& driverPackageName, const std::string& driverVersionName,
- uint64_t driverVersionCode, int64_t driverBuildTime,
- const std::string& appPackageName, const int32_t vulkanVersion,
- GpuStatsInfo::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime) {
+void GpuStats::insertDriverStats(const std::string& driverPackageName,
+ const std::string& driverVersionName, uint64_t driverVersionCode,
+ int64_t driverBuildTime, const std::string& appPackageName,
+ const int32_t vulkanVersion, GpuStatsInfo::Driver driver,
+ bool isDriverLoaded, int64_t driverLoadingTime) {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mLock);
@@ -191,6 +192,11 @@
dumpAll = false;
}
+ if (dumpAll) {
+ dumpGlobalLocked(result);
+ dumpAppLocked(result);
+ }
+
if (argsSet.count("--clear")) {
bool clearAll = true;
@@ -208,13 +214,6 @@
mGlobalStats.clear();
mAppStats.clear();
}
-
- dumpAll = false;
- }
-
- if (dumpAll) {
- dumpGlobalLocked(result);
- dumpAppLocked(result);
}
}
diff --git a/services/gpuservice/gpustats/GpuStats.h b/services/gpuservice/gpustats/include/gpustats/GpuStats.h
similarity index 83%
rename from services/gpuservice/gpustats/GpuStats.h
rename to services/gpuservice/gpustats/include/gpustats/GpuStats.h
index 656b181..bcb9e0d 100644
--- a/services/gpuservice/gpustats/GpuStats.h
+++ b/services/gpuservice/gpustats/include/gpustats/GpuStats.h
@@ -16,15 +16,15 @@
#pragma once
-#include <mutex>
-#include <unordered_map>
-#include <vector>
-
#include <graphicsenv/GpuStatsInfo.h>
#include <graphicsenv/GraphicsEnv.h>
#include <utils/String16.h>
#include <utils/Vector.h>
+#include <mutex>
+#include <unordered_map>
+#include <vector>
+
namespace android {
class GpuStats {
@@ -32,11 +32,12 @@
GpuStats() = default;
~GpuStats() = default;
- // Insert new gpu stats into global stats and app stats.
- void insert(const std::string& driverPackageName, const std::string& driverVersionName,
- uint64_t driverVersionCode, int64_t driverBuildTime,
- const std::string& appPackageName, const int32_t vulkanVersion,
- GpuStatsInfo::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime);
+ // Insert new gpu driver stats into global stats and app stats.
+ void insertDriverStats(const std::string& driverPackageName,
+ const std::string& driverVersionName, uint64_t driverVersionCode,
+ int64_t driverBuildTime, const std::string& appPackageName,
+ const int32_t vulkanVersion, GpuStatsInfo::Driver driver,
+ bool isDriverLoaded, int64_t driverLoadingTime);
// Insert target stats into app stats or potentially global stats as well.
void insertTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode,
const GpuStatsInfo::Stats stats, const uint64_t value);
diff --git a/services/gpuservice/tests/unittests/Android.bp b/services/gpuservice/tests/unittests/Android.bp
new file mode 100644
index 0000000..fee5bd4
--- /dev/null
+++ b/services/gpuservice/tests/unittests/Android.bp
@@ -0,0 +1,34 @@
+// 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.
+
+cc_test {
+ name: "gpuservice_unittest",
+ test_suites: ["device-tests"],
+ sanitize: {
+ address: true,
+ },
+ srcs: [
+ "GpuStatsTest.cpp",
+ ],
+ shared_libs: [
+ "libcutils",
+ "libgfxstats",
+ "libgraphicsenv",
+ "liblog",
+ "libutils",
+ ],
+ static_libs: [
+ "libgmock",
+ ],
+}
diff --git a/services/gpuservice/tests/unittests/AndroidTest.xml b/services/gpuservice/tests/unittests/AndroidTest.xml
new file mode 100644
index 0000000..66f51c7
--- /dev/null
+++ b/services/gpuservice/tests/unittests/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+<configuration description="Config for gpuservice_unittest">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="gpuservice_unittest->/data/local/tmp/gpuservice_unittest" />
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="gpuservice_unittest" />
+ </test>
+</configuration>
diff --git a/services/gpuservice/tests/unittests/GpuStatsTest.cpp b/services/gpuservice/tests/unittests/GpuStatsTest.cpp
new file mode 100644
index 0000000..f038c8a
--- /dev/null
+++ b/services/gpuservice/tests/unittests/GpuStatsTest.cpp
@@ -0,0 +1,253 @@
+/*
+ * 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 "gpuservice_unittest"
+
+#include <cutils/properties.h>
+#include <gmock/gmock.h>
+#include <gpustats/GpuStats.h>
+#include <gtest/gtest.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+namespace android {
+namespace {
+
+using testing::HasSubstr;
+
+// clang-format off
+#define BUILTIN_DRIVER_PKG_NAME "system"
+#define BUILTIN_DRIVER_VER_NAME "0"
+#define BUILTIN_DRIVER_VER_CODE 0
+#define BUILTIN_DRIVER_BUILD_TIME 123
+#define UPDATED_DRIVER_PKG_NAME "updated"
+#define UPDATED_DRIVER_VER_NAME "1"
+#define UPDATED_DRIVER_VER_CODE 1
+#define UPDATED_DRIVER_BUILD_TIME 234
+#define VULKAN_VERSION 345
+#define APP_PKG_NAME_1 "testapp1"
+#define APP_PKG_NAME_2 "testapp2"
+#define DRIVER_LOADING_TIME_1 678
+#define DRIVER_LOADING_TIME_2 789
+#define DRIVER_LOADING_TIME_3 891
+
+enum InputCommand : int32_t {
+ DUMP_ALL = 0,
+ DUMP_GLOBAL = 1,
+ DUMP_APP = 2,
+ DUMP_ALL_THEN_CLEAR = 3,
+ DUMP_GLOBAL_THEN_CLEAR = 4,
+ DUMP_APP_THEN_CLEAR = 5,
+};
+// clang-format on
+
+class GpuStatsTest : public testing::Test {
+public:
+ GpuStatsTest() {
+ 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());
+ }
+
+ ~GpuStatsTest() {
+ 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());
+ }
+
+ std::string inputCommand(InputCommand cmd);
+
+ void SetUp() override {
+ mCpuVulkanVersion = property_get_int32("ro.cpuvulkan.version", 0);
+ mGlesVersion = property_get_int32("ro.opengles.version", 0);
+ }
+
+ std::unique_ptr<GpuStats> mGpuStats = std::make_unique<GpuStats>();
+ int32_t mCpuVulkanVersion = 0;
+ int32_t mGlesVersion = 0;
+};
+
+std::string GpuStatsTest::inputCommand(InputCommand cmd) {
+ std::string result;
+ Vector<String16> args;
+
+ switch (cmd) {
+ case InputCommand::DUMP_ALL:
+ break;
+ case InputCommand::DUMP_GLOBAL:
+ args.push_back(String16("--global"));
+ break;
+ case InputCommand::DUMP_APP:
+ args.push_back(String16("--app"));
+ break;
+ case InputCommand::DUMP_ALL_THEN_CLEAR:
+ args.push_back(String16("--clear"));
+ break;
+ case InputCommand::DUMP_GLOBAL_THEN_CLEAR:
+ args.push_back(String16("--global"));
+ args.push_back(String16("--clear"));
+ break;
+ case InputCommand::DUMP_APP_THEN_CLEAR:
+ args.push_back(String16("--app"));
+ args.push_back(String16("--clear"));
+ break;
+ }
+
+ mGpuStats->dump(args, &result);
+ return result;
+}
+
+TEST_F(GpuStatsTest, statsEmptyByDefault) {
+ ASSERT_TRUE(inputCommand(InputCommand::DUMP_ALL).empty());
+}
+
+TEST_F(GpuStatsTest, canInsertBuiltinDriverStats) {
+ mGpuStats->insertDriverStats(BUILTIN_DRIVER_PKG_NAME, BUILTIN_DRIVER_VER_NAME,
+ BUILTIN_DRIVER_VER_CODE, BUILTIN_DRIVER_BUILD_TIME, APP_PKG_NAME_1,
+ VULKAN_VERSION, GpuStatsInfo::Driver::GL, true,
+ DRIVER_LOADING_TIME_1);
+
+ std::string expectedResult = "driverPackageName = " + std::string(BUILTIN_DRIVER_PKG_NAME);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr(expectedResult));
+ expectedResult = "driverVersionName = " + std::string(BUILTIN_DRIVER_VER_NAME);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr(expectedResult));
+ expectedResult = "driverVersionCode = " + std::to_string(BUILTIN_DRIVER_VER_CODE);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr(expectedResult));
+ expectedResult = "driverBuildTime = " + std::to_string(BUILTIN_DRIVER_BUILD_TIME);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr(expectedResult));
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr("glLoadingCount = 1"));
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr("glLoadingFailureCount = 0"));
+ expectedResult = "appPackageName = " + std::string(APP_PKG_NAME_1);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr(expectedResult));
+ expectedResult = "driverVersionCode = " + std::to_string(BUILTIN_DRIVER_VER_CODE);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr(expectedResult));
+ expectedResult = "glDriverLoadingTime: " + std::to_string(DRIVER_LOADING_TIME_1);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr(expectedResult));
+}
+
+TEST_F(GpuStatsTest, canInsertUpdatedDriverStats) {
+ mGpuStats->insertDriverStats(UPDATED_DRIVER_PKG_NAME, UPDATED_DRIVER_VER_NAME,
+ UPDATED_DRIVER_VER_CODE, UPDATED_DRIVER_BUILD_TIME, APP_PKG_NAME_2,
+ VULKAN_VERSION, GpuStatsInfo::Driver::VULKAN_UPDATED, false,
+ DRIVER_LOADING_TIME_2);
+
+ std::string expectedResult = "driverPackageName = " + std::string(UPDATED_DRIVER_PKG_NAME);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr(expectedResult));
+ expectedResult = "driverVersionName = " + std::string(UPDATED_DRIVER_VER_NAME);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr(expectedResult));
+ expectedResult = "driverVersionCode = " + std::to_string(UPDATED_DRIVER_VER_CODE);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr(expectedResult));
+ expectedResult = "driverBuildTime = " + std::to_string(UPDATED_DRIVER_BUILD_TIME);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr(expectedResult));
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr("vkLoadingCount = 1"));
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr("vkLoadingFailureCount = 1"));
+ expectedResult = "appPackageName = " + std::string(APP_PKG_NAME_2);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr(expectedResult));
+ expectedResult = "driverVersionCode = " + std::to_string(UPDATED_DRIVER_VER_CODE);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr(expectedResult));
+ expectedResult = "vkDriverLoadingTime: " + std::to_string(DRIVER_LOADING_TIME_2);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr(expectedResult));
+}
+
+TEST_F(GpuStatsTest, canInsertAngleDriverStats) {
+ mGpuStats->insertDriverStats(UPDATED_DRIVER_PKG_NAME, UPDATED_DRIVER_VER_NAME,
+ UPDATED_DRIVER_VER_CODE, UPDATED_DRIVER_BUILD_TIME, APP_PKG_NAME_2,
+ VULKAN_VERSION, GpuStatsInfo::Driver::ANGLE, true,
+ DRIVER_LOADING_TIME_3);
+
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr("angleLoadingCount = 1"));
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr("angleLoadingFailureCount = 0"));
+ std::string expectedResult = "angleDriverLoadingTime: " + std::to_string(DRIVER_LOADING_TIME_3);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr(expectedResult));
+}
+
+TEST_F(GpuStatsTest, canDump3dApiVersion) {
+ mGpuStats->insertDriverStats(BUILTIN_DRIVER_PKG_NAME, BUILTIN_DRIVER_VER_NAME,
+ BUILTIN_DRIVER_VER_CODE, BUILTIN_DRIVER_BUILD_TIME, APP_PKG_NAME_1,
+ VULKAN_VERSION, GpuStatsInfo::Driver::GL, true,
+ DRIVER_LOADING_TIME_1);
+
+ std::string expectedResult = "vulkanVersion = " + std::to_string(VULKAN_VERSION);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr(expectedResult));
+ expectedResult = "cpuVulkanVersion = " + std::to_string(mCpuVulkanVersion);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr(expectedResult));
+ expectedResult = "glesVersion = " + std::to_string(mGlesVersion);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr(expectedResult));
+}
+
+TEST_F(GpuStatsTest, canNotInsertTargetStatsBeforeProperSetup) {
+ mGpuStats->insertTargetStats(APP_PKG_NAME_1, BUILTIN_DRIVER_VER_CODE,
+ GpuStatsInfo::Stats::CPU_VULKAN_IN_USE, 0);
+ mGpuStats->insertTargetStats(APP_PKG_NAME_1, BUILTIN_DRIVER_VER_CODE,
+ GpuStatsInfo::Stats::FALSE_PREROTATION, 0);
+ mGpuStats->insertTargetStats(APP_PKG_NAME_1, BUILTIN_DRIVER_VER_CODE,
+ GpuStatsInfo::Stats::GLES_1_IN_USE, 0);
+
+ EXPECT_TRUE(inputCommand(InputCommand::DUMP_APP).empty());
+}
+
+TEST_F(GpuStatsTest, canInsertTargetStatsAfterProperSetup) {
+ mGpuStats->insertDriverStats(BUILTIN_DRIVER_PKG_NAME, BUILTIN_DRIVER_VER_NAME,
+ BUILTIN_DRIVER_VER_CODE, BUILTIN_DRIVER_BUILD_TIME, APP_PKG_NAME_1,
+ VULKAN_VERSION, GpuStatsInfo::Driver::GL, true,
+ DRIVER_LOADING_TIME_1);
+ mGpuStats->insertTargetStats(APP_PKG_NAME_1, BUILTIN_DRIVER_VER_CODE,
+ GpuStatsInfo::Stats::CPU_VULKAN_IN_USE, 0);
+ mGpuStats->insertTargetStats(APP_PKG_NAME_1, BUILTIN_DRIVER_VER_CODE,
+ GpuStatsInfo::Stats::FALSE_PREROTATION, 0);
+ mGpuStats->insertTargetStats(APP_PKG_NAME_1, BUILTIN_DRIVER_VER_CODE,
+ GpuStatsInfo::Stats::GLES_1_IN_USE, 0);
+
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr("cpuVulkanInUse = 1"));
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr("falsePrerotation = 1"));
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr("gles1InUse = 1"));
+}
+
+TEST_F(GpuStatsTest, canDumpAllBeforeClearAll) {
+ mGpuStats->insertDriverStats(BUILTIN_DRIVER_PKG_NAME, BUILTIN_DRIVER_VER_NAME,
+ BUILTIN_DRIVER_VER_CODE, BUILTIN_DRIVER_BUILD_TIME, APP_PKG_NAME_1,
+ VULKAN_VERSION, GpuStatsInfo::Driver::GL, true,
+ DRIVER_LOADING_TIME_1);
+
+ EXPECT_FALSE(inputCommand(InputCommand::DUMP_ALL_THEN_CLEAR).empty());
+ EXPECT_TRUE(inputCommand(InputCommand::DUMP_ALL).empty());
+}
+
+TEST_F(GpuStatsTest, canDumpGlobalBeforeClearGlobal) {
+ mGpuStats->insertDriverStats(BUILTIN_DRIVER_PKG_NAME, BUILTIN_DRIVER_VER_NAME,
+ BUILTIN_DRIVER_VER_CODE, BUILTIN_DRIVER_BUILD_TIME, APP_PKG_NAME_1,
+ VULKAN_VERSION, GpuStatsInfo::Driver::GL, true,
+ DRIVER_LOADING_TIME_1);
+
+ EXPECT_FALSE(inputCommand(InputCommand::DUMP_GLOBAL_THEN_CLEAR).empty());
+ EXPECT_TRUE(inputCommand(InputCommand::DUMP_GLOBAL).empty());
+ EXPECT_FALSE(inputCommand(InputCommand::DUMP_APP).empty());
+}
+
+TEST_F(GpuStatsTest, canDumpAppBeforeClearApp) {
+ mGpuStats->insertDriverStats(BUILTIN_DRIVER_PKG_NAME, BUILTIN_DRIVER_VER_NAME,
+ BUILTIN_DRIVER_VER_CODE, BUILTIN_DRIVER_BUILD_TIME, APP_PKG_NAME_1,
+ VULKAN_VERSION, GpuStatsInfo::Driver::GL, true,
+ DRIVER_LOADING_TIME_1);
+
+ EXPECT_FALSE(inputCommand(InputCommand::DUMP_APP_THEN_CLEAR).empty());
+ EXPECT_TRUE(inputCommand(InputCommand::DUMP_APP).empty());
+ EXPECT_FALSE(inputCommand(InputCommand::DUMP_GLOBAL).empty());
+}
+
+} // namespace
+} // namespace android
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index b2b5145..f2b95e7 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -2686,6 +2686,19 @@
connection->getInputChannelName().c_str(), cancelationEvents.size(), options.reason,
options.mode);
#endif
+
+ InputTarget target;
+ sp<InputWindowHandle> windowHandle =
+ getWindowHandleLocked(connection->inputChannel->getConnectionToken());
+ if (windowHandle != nullptr) {
+ const InputWindowInfo* windowInfo = windowHandle->getInfo();
+ target.setDefaultPointerInfo(-windowInfo->frameLeft, -windowInfo->frameTop,
+ windowInfo->windowXScale, windowInfo->windowYScale);
+ target.globalScaleFactor = windowInfo->globalScaleFactor;
+ }
+ target.inputChannel = connection->inputChannel;
+ target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
+
for (size_t i = 0; i < cancelationEvents.size(); i++) {
EventEntry* cancelationEventEntry = cancelationEvents[i];
switch (cancelationEventEntry->type) {
@@ -2711,18 +2724,6 @@
}
}
- InputTarget target;
- sp<InputWindowHandle> windowHandle =
- getWindowHandleLocked(connection->inputChannel->getConnectionToken());
- if (windowHandle != nullptr) {
- const InputWindowInfo* windowInfo = windowHandle->getInfo();
- target.setDefaultPointerInfo(-windowInfo->frameLeft, -windowInfo->frameTop,
- windowInfo->windowXScale, windowInfo->windowYScale);
- target.globalScaleFactor = windowInfo->globalScaleFactor;
- }
- target.inputChannel = connection->inputChannel;
- target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
-
enqueueDispatchEntryLocked(connection, cancelationEventEntry, // increments ref
target, InputTarget::FLAG_DISPATCH_AS_IS);
@@ -2732,6 +2733,65 @@
startDispatchCycleLocked(currentTime, connection);
}
+void InputDispatcher::synthesizePointerDownEventsForConnectionLocked(
+ const sp<Connection>& connection) {
+ if (connection->status == Connection::STATUS_BROKEN) {
+ return;
+ }
+
+ nsecs_t currentTime = now();
+
+ std::vector<EventEntry*> downEvents =
+ connection->inputState.synthesizePointerDownEvents(currentTime);
+
+ if (downEvents.empty()) {
+ return;
+ }
+
+#if DEBUG_OUTBOUND_EVENT_DETAILS
+ ALOGD("channel '%s' ~ Synthesized %zu down events to ensure consistent event stream.",
+ connection->getInputChannelName().c_str(), downEvents.size());
+#endif
+
+ InputTarget target;
+ sp<InputWindowHandle> windowHandle =
+ getWindowHandleLocked(connection->inputChannel->getConnectionToken());
+ if (windowHandle != nullptr) {
+ const InputWindowInfo* windowInfo = windowHandle->getInfo();
+ target.setDefaultPointerInfo(-windowInfo->frameLeft, -windowInfo->frameTop,
+ windowInfo->windowXScale, windowInfo->windowYScale);
+ target.globalScaleFactor = windowInfo->globalScaleFactor;
+ }
+ target.inputChannel = connection->inputChannel;
+ target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
+
+ for (EventEntry* downEventEntry : downEvents) {
+ switch (downEventEntry->type) {
+ case EventEntry::Type::MOTION: {
+ logOutboundMotionDetails("down - ",
+ static_cast<const MotionEntry&>(*downEventEntry));
+ break;
+ }
+
+ case EventEntry::Type::KEY:
+ case EventEntry::Type::FOCUS:
+ case EventEntry::Type::CONFIGURATION_CHANGED:
+ case EventEntry::Type::DEVICE_RESET: {
+ LOG_ALWAYS_FATAL("%s event should not be found inside Connections's queue",
+ EventEntry::typeToString(downEventEntry->type));
+ break;
+ }
+ }
+
+ enqueueDispatchEntryLocked(connection, downEventEntry, // increments ref
+ target, InputTarget::FLAG_DISPATCH_AS_IS);
+
+ downEventEntry->release();
+ }
+
+ startDispatchCycleLocked(currentTime, connection);
+}
+
MotionEntry* InputDispatcher::splitMotionEvent(const MotionEntry& originalMotionEntry,
BitSet32 pointerIds) {
ALOG_ASSERT(pointerIds.value != 0);
@@ -3770,11 +3830,12 @@
sp<Connection> fromConnection = getConnectionLocked(fromToken);
sp<Connection> toConnection = getConnectionLocked(toToken);
if (fromConnection != nullptr && toConnection != nullptr) {
- fromConnection->inputState.copyPointerStateTo(toConnection->inputState);
+ fromConnection->inputState.mergePointerStateTo(toConnection->inputState);
CancelationOptions
options(CancelationOptions::CANCEL_POINTER_EVENTS,
"transferring touch focus from this window to another window");
synthesizeCancelationEventsForConnectionLocked(fromConnection, options);
+ synthesizePointerDownEventsForConnectionLocked(toConnection);
}
if (DEBUG_FOCUS) {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 93de18d..d2aea80 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -417,6 +417,9 @@
const CancelationOptions& options)
REQUIRES(mLock);
+ void synthesizePointerDownEventsForConnectionLocked(const sp<Connection>& connection)
+ REQUIRES(mLock);
+
// Splitting motion events across windows.
MotionEntry* splitMotionEvent(const MotionEntry& originalMotionEntry, BitSet32 pointerIds);
diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp
index c43e304..053598a 100644
--- a/services/inputflinger/dispatcher/InputState.cpp
+++ b/services/inputflinger/dispatcher/InputState.cpp
@@ -145,10 +145,13 @@
// Joysticks and trackballs can send MOVE events without corresponding DOWN or UP.
return true;
}
+
if (index >= 0) {
MotionMemento& memento = mMotionMementos[index];
- memento.setPointers(entry);
- return true;
+ if (memento.firstNewPointerIdx < 0) {
+ memento.setPointers(entry);
+ return true;
+ }
}
#if DEBUG_OUTBOUND_EVENT_DETAILS
ALOGD("Dropping inconsistent motion pointer up/down or move event: "
@@ -249,6 +252,17 @@
}
}
+void InputState::MotionMemento::mergePointerStateTo(MotionMemento& other) const {
+ for (uint32_t i = 0; i < pointerCount; i++) {
+ if (other.firstNewPointerIdx < 0) {
+ other.firstNewPointerIdx = other.pointerCount;
+ }
+ other.pointerProperties[other.pointerCount].copyFrom(pointerProperties[i]);
+ other.pointerCoords[other.pointerCount].copyFrom(pointerCoords[i]);
+ other.pointerCount++;
+ }
+}
+
std::vector<EventEntry*> InputState::synthesizeCancelationEvents(
nsecs_t currentTime, const CancelationOptions& options) {
std::vector<EventEntry*> events;
@@ -282,27 +296,87 @@
return events;
}
+std::vector<EventEntry*> InputState::synthesizePointerDownEvents(nsecs_t currentTime) {
+ std::vector<EventEntry*> events;
+ for (MotionMemento& memento : mMotionMementos) {
+ if (!(memento.source & AINPUT_SOURCE_CLASS_POINTER)) {
+ continue;
+ }
+
+ if (memento.firstNewPointerIdx < 0) {
+ continue;
+ }
+
+ uint32_t pointerCount = 0;
+ PointerProperties pointerProperties[MAX_POINTERS];
+ PointerCoords pointerCoords[MAX_POINTERS];
+
+ // We will deliver all pointers the target already knows about
+ for (uint32_t i = 0; i < static_cast<uint32_t>(memento.firstNewPointerIdx); i++) {
+ pointerProperties[i].copyFrom(memento.pointerProperties[i]);
+ pointerCoords[i].copyFrom(memento.pointerCoords[i]);
+ pointerCount++;
+ }
+
+ // We will send explicit events for all pointers the target doesn't know about
+ for (uint32_t i = static_cast<uint32_t>(memento.firstNewPointerIdx);
+ i < memento.pointerCount; i++) {
+
+ pointerProperties[i].copyFrom(memento.pointerProperties[i]);
+ pointerCoords[i].copyFrom(memento.pointerCoords[i]);
+ pointerCount++;
+
+ // Down only if the first pointer, pointer down otherwise
+ const int32_t action = (pointerCount <= 1)
+ ? AMOTION_EVENT_ACTION_DOWN
+ : AMOTION_EVENT_ACTION_POINTER_DOWN
+ | (i << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+
+ events.push_back(new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime,
+ memento.deviceId, memento.source, memento.displayId,
+ memento.policyFlags, action, 0 /*actionButton*/,
+ memento.flags, AMETA_NONE, 0 /*buttonState*/,
+ MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
+ memento.yPrecision, memento.xCursorPosition,
+ memento.yCursorPosition, memento.downTime,
+ pointerCount, pointerProperties,
+ pointerCoords, 0 /*xOffset*/, 0 /*yOffset*/));
+ }
+
+ memento.firstNewPointerIdx = INVALID_POINTER_INDEX;
+ }
+
+ return events;
+}
+
void InputState::clear() {
mKeyMementos.clear();
mMotionMementos.clear();
mFallbackKeys.clear();
}
-void InputState::copyPointerStateTo(InputState& other) const {
+void InputState::mergePointerStateTo(InputState& other) {
for (size_t i = 0; i < mMotionMementos.size(); i++) {
- const MotionMemento& memento = mMotionMementos[i];
+ MotionMemento& memento = mMotionMementos[i];
+ // Since we support split pointers we need to merge touch events
+ // from the same source + device + screen.
if (memento.source & AINPUT_SOURCE_CLASS_POINTER) {
- for (size_t j = 0; j < other.mMotionMementos.size();) {
- const MotionMemento& otherMemento = other.mMotionMementos[j];
+ bool merged = false;
+ for (size_t j = 0; j < other.mMotionMementos.size(); j++) {
+ MotionMemento& otherMemento = other.mMotionMementos[j];
if (memento.deviceId == otherMemento.deviceId &&
memento.source == otherMemento.source &&
memento.displayId == otherMemento.displayId) {
- other.mMotionMementos.erase(other.mMotionMementos.begin() + j);
- } else {
- j += 1;
+ memento.mergePointerStateTo(otherMemento);
+ merged = true;
+ break;
}
}
- other.mMotionMementos.push_back(memento);
+ if (!merged) {
+ memento.firstNewPointerIdx = 0;
+ other.mMotionMementos.push_back(memento);
+ }
}
}
}
diff --git a/services/inputflinger/dispatcher/InputState.h b/services/inputflinger/dispatcher/InputState.h
index a93f486..08266ae 100644
--- a/services/inputflinger/dispatcher/InputState.h
+++ b/services/inputflinger/dispatcher/InputState.h
@@ -24,6 +24,8 @@
namespace android::inputdispatcher {
+static constexpr int32_t INVALID_POINTER_INDEX = -1;
+
/* Tracks dispatched key and motion event state so that cancellation events can be
* synthesized when events are dropped. */
class InputState {
@@ -52,11 +54,14 @@
std::vector<EventEntry*> synthesizeCancelationEvents(nsecs_t currentTime,
const CancelationOptions& options);
+ // Synthesizes down events for the current state.
+ std::vector<EventEntry*> synthesizePointerDownEvents(nsecs_t currentTime);
+
// Clears the current state.
void clear();
- // Copies pointer-related parts of the input state to another instance.
- void copyPointerStateTo(InputState& other) const;
+ // Merges pointer-related parts of the input state into another instance.
+ void mergePointerStateTo(InputState& other);
// Gets the fallback key associated with a keycode.
// Returns -1 if none.
@@ -97,10 +102,13 @@
uint32_t pointerCount;
PointerProperties pointerProperties[MAX_POINTERS];
PointerCoords pointerCoords[MAX_POINTERS];
+ // Track for which pointers the target doesn't know about.
+ int32_t firstNewPointerIdx = INVALID_POINTER_INDEX;
bool hovering;
uint32_t policyFlags;
void setPointers(const MotionEntry& entry);
+ void mergePointerStateTo(MotionMemento& other) const;
};
std::vector<KeyMemento> mKeyMementos;
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 094452a..27db8f5 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -594,12 +594,40 @@
expectedFlags);
}
- void consumeMotionDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
+ void consumeMotionCancel(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT,
+ int32_t expectedFlags = 0) {
+ consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_CANCEL, expectedDisplayId,
+ expectedFlags);
+ }
+
+ void consumeMotionMove(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT,
+ int32_t expectedFlags = 0) {
+ consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_MOVE, expectedDisplayId,
+ expectedFlags);
+ }
+
+ void consumeMotionDown(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT,
+ int32_t expectedFlags = 0) {
consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_DOWN, expectedDisplayId,
expectedFlags);
}
- void consumeMotionUp(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
+ void consumeMotionPointerDown(int32_t pointerIdx,
+ int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, int32_t expectedFlags = 0) {
+ int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN
+ | (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+ consumeEvent(AINPUT_EVENT_TYPE_MOTION, action, expectedDisplayId, expectedFlags);
+ }
+
+ void consumeMotionPointerUp(int32_t pointerIdx, int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT,
+ int32_t expectedFlags = 0) {
+ int32_t action = AMOTION_EVENT_ACTION_POINTER_UP
+ | (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+ consumeEvent(AINPUT_EVENT_TYPE_MOTION, action, expectedDisplayId, expectedFlags);
+ }
+
+ void consumeMotionUp(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT,
+ int32_t expectedFlags = 0) {
consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_UP, expectedDisplayId,
expectedFlags);
}
@@ -923,6 +951,161 @@
0 /*expectedFlags*/);
}
+TEST_F(InputDispatcherTest, TransferTouchFocus_OnePointer) {
+ sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+
+ // Create a couple of windows
+ sp<FakeWindowHandle> firstWindow = new FakeWindowHandle(application, mDispatcher,
+ "First Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> secondWindow = new FakeWindowHandle(application, mDispatcher,
+ "Second Window", ADISPLAY_ID_DEFAULT);
+
+ // Add the windows to the dispatcher
+ mDispatcher->setInputWindows({firstWindow, secondWindow}, ADISPLAY_ID_DEFAULT);
+
+ // Send down to the first window
+ NotifyMotionArgs downMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
+ AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyMotion(&downMotionArgs);
+ // Only the first window should get the down event
+ firstWindow->consumeMotionDown();
+ secondWindow->assertNoEvents();
+
+ // Transfer touch focus to the second window
+ mDispatcher->transferTouchFocus(firstWindow->getToken(), secondWindow->getToken());
+ // The first window gets cancel and the second gets down
+ firstWindow->consumeMotionCancel();
+ secondWindow->consumeMotionDown();
+
+ // Send up event to the second window
+ NotifyMotionArgs upMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_UP,
+ AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyMotion(&upMotionArgs);
+ // The first window gets no events and the second gets up
+ firstWindow->assertNoEvents();
+ secondWindow->consumeMotionUp();
+}
+
+TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointerNoSplitTouch) {
+ sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+
+ PointF touchPoint = {10, 10};
+
+ // Create a couple of windows
+ sp<FakeWindowHandle> firstWindow = new FakeWindowHandle(application, mDispatcher,
+ "First Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> secondWindow = new FakeWindowHandle(application, mDispatcher,
+ "Second Window", ADISPLAY_ID_DEFAULT);
+
+ // Add the windows to the dispatcher
+ mDispatcher->setInputWindows({firstWindow, secondWindow}, ADISPLAY_ID_DEFAULT);
+
+ // Send down to the first window
+ NotifyMotionArgs downMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
+ AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {touchPoint});
+ mDispatcher->notifyMotion(&downMotionArgs);
+ // Only the first window should get the down event
+ firstWindow->consumeMotionDown();
+ secondWindow->assertNoEvents();
+
+ // Send pointer down to the first window
+ NotifyMotionArgs pointerDownMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_DOWN
+ | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint});
+ mDispatcher->notifyMotion(&pointerDownMotionArgs);
+ // Only the first window should get the pointer down event
+ firstWindow->consumeMotionPointerDown(1);
+ secondWindow->assertNoEvents();
+
+ // Transfer touch focus to the second window
+ mDispatcher->transferTouchFocus(firstWindow->getToken(), secondWindow->getToken());
+ // The first window gets cancel and the second gets down and pointer down
+ firstWindow->consumeMotionCancel();
+ secondWindow->consumeMotionDown();
+ secondWindow->consumeMotionPointerDown(1);
+
+ // Send pointer up to the second window
+ NotifyMotionArgs pointerUpMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_UP
+ | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint});
+ mDispatcher->notifyMotion(&pointerUpMotionArgs);
+ // The first window gets nothing and the second gets pointer up
+ firstWindow->assertNoEvents();
+ secondWindow->consumeMotionPointerUp(1);
+
+ // Send up event to the second window
+ NotifyMotionArgs upMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_UP,
+ AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyMotion(&upMotionArgs);
+ // The first window gets nothing and the second gets up
+ firstWindow->assertNoEvents();
+ secondWindow->consumeMotionUp();
+}
+
+TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) {
+ sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+
+ // Create a non touch modal window that supports split touch
+ sp<FakeWindowHandle> firstWindow = new FakeWindowHandle(application, mDispatcher,
+ "First Window", ADISPLAY_ID_DEFAULT);
+ firstWindow->setFrame(Rect(0, 0, 600, 400));
+ firstWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL
+ | InputWindowInfo::FLAG_SPLIT_TOUCH);
+
+ // Create a non touch modal window that supports split touch
+ sp<FakeWindowHandle> secondWindow = new FakeWindowHandle(application, mDispatcher,
+ "Second Window", ADISPLAY_ID_DEFAULT);
+ secondWindow->setFrame(Rect(0, 400, 600, 800));
+ secondWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL
+ | InputWindowInfo::FLAG_SPLIT_TOUCH);
+
+ // Add the windows to the dispatcher
+ mDispatcher->setInputWindows({firstWindow, secondWindow}, ADISPLAY_ID_DEFAULT);
+
+ PointF pointInFirst = {300, 200};
+ PointF pointInSecond = {300, 600};
+
+ // Send down to the first window
+ NotifyMotionArgs firstDownMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
+ AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {pointInFirst});
+ mDispatcher->notifyMotion(&firstDownMotionArgs);
+ // Only the first window should get the down event
+ firstWindow->consumeMotionDown();
+ secondWindow->assertNoEvents();
+
+ // Send down to the second window
+ NotifyMotionArgs secondDownMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_DOWN
+ | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {pointInFirst, pointInSecond});
+ mDispatcher->notifyMotion(&secondDownMotionArgs);
+ // The first window gets a move and the second a down
+ firstWindow->consumeMotionMove();
+ secondWindow->consumeMotionDown();
+
+ // Transfer touch focus to the second window
+ mDispatcher->transferTouchFocus(firstWindow->getToken(), secondWindow->getToken());
+ // The first window gets cancel and the new gets pointer down (it already saw down)
+ firstWindow->consumeMotionCancel();
+ secondWindow->consumeMotionPointerDown(1);
+
+ // Send pointer up to the second window
+ NotifyMotionArgs pointerUpMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_UP
+ | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {pointInFirst, pointInSecond});
+ mDispatcher->notifyMotion(&pointerUpMotionArgs);
+ // The first window gets nothing and the second gets pointer up
+ firstWindow->assertNoEvents();
+ secondWindow->consumeMotionPointerUp(1);
+
+ // Send up event to the second window
+ NotifyMotionArgs upMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_UP,
+ AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyMotion(&upMotionArgs);
+ // The first window gets nothing and the second gets up
+ firstWindow->assertNoEvents();
+ secondWindow->consumeMotionUp();
+}
+
TEST_F(InputDispatcherTest, FocusedWindow_ReceivesFocusEventAndKeyEvent) {
sp<FakeApplicationHandle> application = new FakeApplicationHandle();
sp<FakeWindowHandle> window =
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 35d0215..f4f45be 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -26,8 +26,6 @@
#include "BufferLayer.h"
#include <compositionengine/CompositionEngine.h>
-#include <compositionengine/Layer.h>
-#include <compositionengine/LayerCreationArgs.h>
#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/OutputLayer.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
@@ -66,8 +64,7 @@
BufferLayer::BufferLayer(const LayerCreationArgs& args)
: Layer(args),
mTextureName(args.textureName),
- mCompositionLayer{mFlinger->getCompositionEngine().createLayer(
- compositionengine::LayerCreationArgs{this})} {
+ mCompositionState{mFlinger->getCompositionEngine().createLayerFECompositionState()} {
ALOGV("Creating Layer %s", getDebugName());
mPremultipliedAlpha = !(args.flags & ISurfaceComposerClient::eNonPremultiplied);
@@ -184,7 +181,7 @@
bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) ||
(isSecure() && !targetSettings.isSecure);
const State& s(getDrawingState());
- LayerFE::LayerSettings& layer = *result;
+ compositionengine::LayerFE::LayerSettings& layer = *result;
if (!blackOutLayer) {
layer.source.buffer.buffer = mBufferInfo.mBuffer;
layer.source.buffer.isOpaque = isOpaque(s);
@@ -282,17 +279,29 @@
mBufferInfo.mBuffer->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102);
}
-void BufferLayer::latchPerFrameState(
- compositionengine::LayerFECompositionState& compositionState) const {
- Layer::latchPerFrameState(compositionState);
+sp<compositionengine::LayerFE> BufferLayer::getCompositionEngineLayerFE() const {
+ return asLayerFE();
+}
+
+compositionengine::LayerFECompositionState* BufferLayer::editCompositionState() {
+ return mCompositionState.get();
+}
+
+const compositionengine::LayerFECompositionState* BufferLayer::getCompositionState() const {
+ return mCompositionState.get();
+}
+
+void BufferLayer::preparePerFrameCompositionState() {
+ Layer::preparePerFrameCompositionState();
// Sideband layers
- if (compositionState.sidebandStream.get()) {
- compositionState.compositionType = Hwc2::IComposerClient::Composition::SIDEBAND;
+ auto* compositionState = editCompositionState();
+ if (compositionState->sidebandStream.get()) {
+ compositionState->compositionType = Hwc2::IComposerClient::Composition::SIDEBAND;
} else {
// Normal buffer layers
- compositionState.hdrMetadata = mBufferInfo.mHdrMetadata;
- compositionState.compositionType = mPotentialCursor
+ compositionState->hdrMetadata = mBufferInfo.mHdrMetadata;
+ compositionState->compositionType = mPotentialCursor
? Hwc2::IComposerClient::Composition::CURSOR
: Hwc2::IComposerClient::Composition::DEVICE;
}
@@ -641,10 +650,6 @@
return Rect(bufWidth, bufHeight);
}
-std::shared_ptr<compositionengine::Layer> BufferLayer::getCompositionLayer() const {
- return mCompositionLayer;
-}
-
FloatRect BufferLayer::computeSourceBounds(const FloatRect& parentBounds) const {
const State& s(getDrawingState());
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index b2398a8..4085b52 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -54,7 +54,8 @@
// Overriden from Layer
// -----------------------------------------------------------------------
public:
- std::shared_ptr<compositionengine::Layer> getCompositionLayer() const override;
+ sp<compositionengine::LayerFE> getCompositionEngineLayerFE() const override;
+ compositionengine::LayerFECompositionState* editCompositionState() override;
// If we have received a new buffer this frame, we will pass its surface
// damage down to hardware composer. Otherwise, we must send a region with
@@ -175,8 +176,9 @@
/*
* compositionengine::LayerFE overrides
*/
+ const compositionengine::LayerFECompositionState* getCompositionState() const override;
bool onPreComposition(nsecs_t) override;
- void latchPerFrameState(compositionengine::LayerFECompositionState&) const override;
+ void preparePerFrameCompositionState() override;
std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition(
compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
@@ -210,7 +212,7 @@
// and its parent layer is not bounded
Rect getBufferSize(const State& s) const override;
- std::shared_ptr<compositionengine::Layer> mCompositionLayer;
+ std::unique_ptr<compositionengine::LayerFECompositionState> mCompositionState;
FloatRect computeSourceBounds(const FloatRect& parentBounds) const override;
};
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 6423893..3cc803e 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -23,7 +23,6 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include "BufferQueueLayer.h"
-#include <compositionengine/Layer.h>
#include <compositionengine/LayerFECompositionState.h>
#include <gui/BufferQueueConsumer.h>
#include <system/window.h>
@@ -125,21 +124,16 @@
return isDue || !isPlausible;
}
-bool BufferQueueLayer::setFrameRate(float frameRate) {
+bool BufferQueueLayer::setFrameRate(FrameRate frameRate) {
float oldFrameRate = 0.f;
status_t result = mConsumer->getFrameRate(&oldFrameRate);
- bool frameRateChanged = result < 0 || frameRate != oldFrameRate;
- mConsumer->setFrameRate(frameRate);
+ bool frameRateChanged = result < 0 || frameRate.rate != oldFrameRate;
+ mConsumer->setFrameRate(frameRate.rate);
return frameRateChanged;
}
-std::optional<float> BufferQueueLayer::getFrameRate() const {
- const auto frameRate = mLatchedFrameRate.load();
- if (frameRate > 0.f || frameRate == FRAME_RATE_NO_VOTE) {
- return frameRate;
- }
-
- return {};
+Layer::FrameRate BufferQueueLayer::getFrameRate() const {
+ return FrameRate(mLatchedFrameRate, Layer::FrameRateCompatibility::Default);
}
// -----------------------------------------------------------------------
@@ -228,9 +222,9 @@
if (mSidebandStreamChanged.compare_exchange_strong(sidebandStreamChanged, false)) {
// mSidebandStreamChanged was changed to false
mSidebandStream = mConsumer->getSidebandStream();
- auto& layerCompositionState = getCompositionLayer()->editFEState();
- layerCompositionState.sidebandStream = mSidebandStream;
- if (layerCompositionState.sidebandStream != nullptr) {
+ auto* layerCompositionState = editCompositionState();
+ layerCompositionState->sidebandStream = mSidebandStream;
+ if (layerCompositionState->sidebandStream != nullptr) {
setTransactionFlags(eTransactionNeeded);
mFlinger->setTransactionFlags(eTraversalNeeded);
}
@@ -364,8 +358,8 @@
mPreviousBufferId = getCurrentBufferId();
mBufferInfo.mBuffer =
mConsumer->getCurrentBuffer(&mBufferInfo.mBufferSlot, &mBufferInfo.mFence);
- auto& layerCompositionState = getCompositionLayer()->editFEState();
- layerCompositionState.buffer = mBufferInfo.mBuffer;
+ auto* layerCompositionState = editCompositionState();
+ layerCompositionState->buffer = mBufferInfo.mBuffer;
if (mBufferInfo.mBuffer == nullptr) {
// this can only happen if the very first buffer was rejected.
@@ -385,18 +379,19 @@
return NO_ERROR;
}
-void BufferQueueLayer::latchPerFrameState(
- compositionengine::LayerFECompositionState& compositionState) const {
- BufferLayer::latchPerFrameState(compositionState);
- if (compositionState.compositionType == Hwc2::IComposerClient::Composition::SIDEBAND) {
+void BufferQueueLayer::preparePerFrameCompositionState() {
+ BufferLayer::preparePerFrameCompositionState();
+
+ auto* compositionState = editCompositionState();
+ if (compositionState->compositionType == Hwc2::IComposerClient::Composition::SIDEBAND) {
return;
}
- compositionState.buffer = mBufferInfo.mBuffer;
- compositionState.bufferSlot = (mBufferInfo.mBufferSlot == BufferQueue::INVALID_BUFFER_SLOT)
+ compositionState->buffer = mBufferInfo.mBuffer;
+ compositionState->bufferSlot = (mBufferInfo.mBufferSlot == BufferQueue::INVALID_BUFFER_SLOT)
? 0
: mBufferInfo.mBufferSlot;
- compositionState.acquireFence = mBufferInfo.mFence;
+ compositionState->acquireFence = mBufferInfo.mFence;
}
// -----------------------------------------------------------------------
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 2bd1e3d..626af4b 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -56,8 +56,8 @@
bool shouldPresentNow(nsecs_t expectedPresentTime) const override;
- bool setFrameRate(float frameRate) override;
- std::optional<float> getFrameRate() const override;
+ bool setFrameRate(FrameRate frameRate) override;
+ FrameRate getFrameRate() const override;
// -----------------------------------------------------------------------
@@ -85,7 +85,7 @@
status_t updateActiveBuffer() override;
status_t updateFrameNumber(nsecs_t latchTime) override;
- void latchPerFrameState(compositionengine::LayerFECompositionState&) const override;
+ void preparePerFrameCompositionState() override;
sp<Layer> createClone() override;
void onFrameAvailable(const BufferItem& item);
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 278ad52..923a81c 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -27,7 +27,6 @@
#include <limits>
-#include <compositionengine/Layer.h>
#include <compositionengine/LayerFECompositionState.h>
#include <gui/BufferQueue.h>
#include <private/gui/SyncFeatures.h>
@@ -98,6 +97,8 @@
}
}
+ mPreviousReleaseFence = releaseFence;
+
// Prevent tracing the same release multiple times.
if (mPreviousFrameNumber != mPreviousReleasedFrameNumber) {
mFlinger->mFrameTracer->traceFence(getSequence(), mPreviousBufferId, mPreviousFrameNumber,
@@ -111,15 +112,34 @@
mTransformHint = orientation;
}
-void BufferStateLayer::releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) {
+void BufferStateLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
for (const auto& handle : mDrawingState.callbackHandles) {
handle->transformHint = mTransformHint;
+ handle->dequeueReadyTime = dequeueReadyTime;
}
mFlinger->getTransactionCompletedThread().finalizePendingCallbackHandles(
mDrawingState.callbackHandles);
mDrawingState.callbackHandles = {};
+
+ const sp<Fence>& releaseFence(mPreviousReleaseFence);
+ std::shared_ptr<FenceTime> releaseFenceTime = std::make_shared<FenceTime>(releaseFence);
+ {
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+ if (mPreviousFrameNumber != 0) {
+ mFrameEventHistory.addRelease(mPreviousFrameNumber, dequeueReadyTime,
+ std::move(releaseFenceTime));
+ }
+ }
+}
+
+void BufferStateLayer::finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& glDoneFence,
+ const CompositorTiming& compositorTiming) {
+ for (const auto& handle : mDrawingState.callbackHandles) {
+ handle->gpuCompositionDoneFence = glDoneFence;
+ handle->compositorTiming = compositorTiming;
+ }
}
bool BufferStateLayer::shouldPresentNow(nsecs_t /*expectedPresentTime*/) const {
@@ -138,6 +158,8 @@
!mLayerDetached;
}
+/* TODO: vhau uncomment once deferred transaction migration complete in
+ * WindowManager
void BufferStateLayer::pushPendingState() {
if (!mCurrentState.modified) {
return;
@@ -145,13 +167,12 @@
mPendingStates.push_back(mCurrentState);
ATRACE_INT(mTransactionName.c_str(), mPendingStates.size());
}
+*/
bool BufferStateLayer::applyPendingStates(Layer::State* stateToCommit) {
- const bool stateUpdateAvailable = !mPendingStates.empty();
- while (!mPendingStates.empty()) {
- popPendingState(stateToCommit);
- }
- mCurrentStateModified = stateUpdateAvailable && mCurrentState.modified;
+ mCurrentStateModified = mCurrentState.modified;
+ bool stateUpdateAvailable = Layer::applyPendingStates(stateToCommit);
+ mCurrentStateModified = stateUpdateAvailable && mCurrentStateModified;
mCurrentState.modified = false;
return stateUpdateAvailable;
}
@@ -233,8 +254,22 @@
return true;
}
-bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, nsecs_t postTime,
- nsecs_t desiredPresentTime, const client_cache_t& clientCacheId) {
+bool BufferStateLayer::addFrameEvent(const sp<Fence>& acquireFence, nsecs_t postedTime,
+ nsecs_t desiredPresentTime) {
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+ mAcquireTimeline.updateSignalTimes();
+ std::shared_ptr<FenceTime> acquireFenceTime =
+ std::make_shared<FenceTime>((acquireFence ? acquireFence : Fence::NO_FENCE));
+ NewFrameEventsEntry newTimestamps = {mCurrentState.frameNumber, postedTime, desiredPresentTime,
+ acquireFenceTime};
+ mFrameEventHistory.setProducerWantsEvents();
+ mFrameEventHistory.addQueue(newTimestamps);
+ return true;
+}
+
+bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& acquireFence,
+ nsecs_t postTime, nsecs_t desiredPresentTime,
+ const client_cache_t& clientCacheId) {
if (mCurrentState.buffer) {
mReleasePreviousBuffer = true;
}
@@ -252,11 +287,12 @@
mFlinger->mFrameTracer->traceNewLayer(layerId, getName().c_str());
mFlinger->mFrameTracer->traceTimestamp(layerId, buffer->getId(), mCurrentState.frameNumber,
postTime, FrameTracer::FrameEvent::POST);
+ desiredPresentTime = desiredPresentTime <= 0 ? 0 : desiredPresentTime;
mCurrentState.desiredPresentTime = desiredPresentTime;
- mFlinger->mScheduler->recordLayerHistory(this,
- desiredPresentTime <= 0 ? 0 : desiredPresentTime);
+ mFlinger->mScheduler->recordLayerHistory(this, desiredPresentTime);
+ addFrameEvent(acquireFence, postTime, desiredPresentTime);
return true;
}
@@ -421,6 +457,13 @@
return mCurrentState.desiredPresentTime <= expectedPresentTime;
}
+bool BufferStateLayer::onPreComposition(nsecs_t refreshStartTime) {
+ for (const auto& handle : mDrawingState.callbackHandles) {
+ handle->refreshStartTime = refreshStartTime;
+ }
+ return BufferLayer::onPreComposition(refreshStartTime);
+}
+
uint64_t BufferStateLayer::getFrameNumber(nsecs_t /*expectedPresentTime*/) const {
return mDrawingState.frameNumber;
}
@@ -438,9 +481,8 @@
if (mSidebandStreamChanged.exchange(false)) {
const State& s(getDrawingState());
// mSidebandStreamChanged was true
- LOG_ALWAYS_FATAL_IF(!getCompositionLayer());
mSidebandStream = s.sidebandStream;
- getCompositionLayer()->editFEState().sidebandStream = mSidebandStream;
+ editCompositionState()->sidebandStream = mSidebandStream;
if (mSidebandStream != nullptr) {
setTransactionFlags(eTransactionNeeded);
mFlinger->setTransactionFlags(eTraversalNeeded);
@@ -505,6 +547,7 @@
for (auto& handle : mDrawingState.callbackHandles) {
handle->latchTime = latchTime;
+ handle->frameNumber = mDrawingState.frameNumber;
}
if (!SyncFeatures::getInstance().useNativeFenceSync()) {
@@ -547,29 +590,33 @@
mPreviousBufferId = getCurrentBufferId();
mBufferInfo.mBuffer = s.buffer;
mBufferInfo.mFence = s.acquireFence;
- auto& layerCompositionState = getCompositionLayer()->editFEState();
- layerCompositionState.buffer = mBufferInfo.mBuffer;
+ editCompositionState()->buffer = mBufferInfo.mBuffer;
return NO_ERROR;
}
-status_t BufferStateLayer::updateFrameNumber(nsecs_t /*latchTime*/) {
+status_t BufferStateLayer::updateFrameNumber(nsecs_t latchTime) {
// TODO(marissaw): support frame history events
mPreviousFrameNumber = mCurrentFrameNumber;
mCurrentFrameNumber = mDrawingState.frameNumber;
+ {
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+ mFrameEventHistory.addLatch(mCurrentFrameNumber, latchTime);
+ }
return NO_ERROR;
}
-void BufferStateLayer::latchPerFrameState(
- compositionengine::LayerFECompositionState& compositionState) const {
- BufferLayer::latchPerFrameState(compositionState);
- if (compositionState.compositionType == Hwc2::IComposerClient::Composition::SIDEBAND) {
+void BufferStateLayer::preparePerFrameCompositionState() {
+ BufferLayer::preparePerFrameCompositionState();
+
+ auto* compositionState = editCompositionState();
+ if (compositionState->compositionType == Hwc2::IComposerClient::Composition::SIDEBAND) {
return;
}
- compositionState.buffer = mBufferInfo.mBuffer;
- compositionState.bufferSlot = mBufferInfo.mBufferSlot;
- compositionState.acquireFence = mBufferInfo.mFence;
+ compositionState->buffer = mBufferInfo.mBuffer;
+ compositionState->bufferSlot = mBufferInfo.mBufferSlot;
+ compositionState->acquireFence = mBufferInfo.mFence;
}
void BufferStateLayer::HwcSlotGenerator::bufferErased(const client_cache_t& clientCacheId) {
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 9427283..6ee5802 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -45,12 +45,17 @@
void setTransformHint(uint32_t orientation) const override;
void releasePendingBuffer(nsecs_t dequeueReadyTime) override;
+ void finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& glDoneFence,
+ const CompositorTiming& compositorTiming) override;
+
bool shouldPresentNow(nsecs_t expectedPresentTime) const override;
uint32_t doTransactionResize(uint32_t flags, Layer::State* /*stateToCommit*/) override {
return flags;
}
- void pushPendingState() override;
+ /*TODO:vhau return to using BufferStateLayer override once WM
+ * has removed deferred transactions!
+ void pushPendingState() override;*/
bool applyPendingStates(Layer::State* stateToCommit) override;
uint32_t getActiveWidth(const Layer::State& s) const override { return s.active.w; }
@@ -68,8 +73,8 @@
bool setTransformToDisplayInverse(bool transformToDisplayInverse) override;
bool setCrop(const Rect& crop) override;
bool setFrame(const Rect& frame) override;
- bool setBuffer(const sp<GraphicBuffer>& buffer, nsecs_t postTime, nsecs_t desiredPresentTime,
- const client_cache_t& clientCacheId) override;
+ bool setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& acquireFence, nsecs_t postTime,
+ nsecs_t desiredPresentTime, const client_cache_t& clientCacheId) override;
bool setAcquireFence(const sp<Fence>& fence) override;
bool setDataspace(ui::Dataspace dataspace) override;
bool setHdrMetadata(const HdrMetadata& hdrMetadata) override;
@@ -78,6 +83,8 @@
bool setSidebandStream(const sp<NativeHandle>& sidebandStream) override;
bool setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& handles) override;
void forceSendCallbacks() override;
+ bool addFrameEvent(const sp<Fence>& acquireFence, nsecs_t postedTime,
+ nsecs_t requestedPresentTime) override;
// Override to ignore legacy layer state properties that are not used by BufferStateLayer
bool setSize(uint32_t /*w*/, uint32_t /*h*/) override { return false; }
@@ -104,11 +111,15 @@
// -----------------------------------------------------------------------
bool fenceHasSignaled() const override;
bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const override;
+ bool onPreComposition(nsecs_t refreshStartTime) override;
protected:
void gatherBufferInfo() override;
private:
+ bool updateFrameEventHistory(const sp<Fence>& acquireFence, nsecs_t postedTime,
+ nsecs_t requestedPresentTime);
+
uint64_t getFrameNumber(nsecs_t expectedPresentTime) const override;
bool getAutoRefresh() const override;
@@ -125,7 +136,7 @@
status_t updateActiveBuffer() override;
status_t updateFrameNumber(nsecs_t latchTime) override;
- void latchPerFrameState(compositionengine::LayerFECompositionState&) const override;
+ void preparePerFrameCompositionState() override;
sp<Layer> createClone() override;
// Crop that applies to the buffer
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index dbdfd5b..83050c4 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -29,8 +29,6 @@
#include <sys/types.h>
#include <compositionengine/CompositionEngine.h>
-#include <compositionengine/Layer.h>
-#include <compositionengine/LayerCreationArgs.h>
#include <compositionengine/LayerFECompositionState.h>
#include <renderengine/RenderEngine.h>
#include <ui/GraphicBuffer.h>
@@ -45,8 +43,7 @@
ColorLayer::ColorLayer(const LayerCreationArgs& args)
: Layer(args),
- mCompositionLayer{mFlinger->getCompositionEngine().createLayer(
- compositionengine::LayerCreationArgs{this})} {}
+ mCompositionState{mFlinger->getCompositionEngine().createLayerFECompositionState()} {}
ColorLayer::~ColorLayer() = default;
@@ -91,16 +88,24 @@
return true;
}
-void ColorLayer::latchPerFrameState(
- compositionengine::LayerFECompositionState& compositionState) const {
- Layer::latchPerFrameState(compositionState);
+void ColorLayer::preparePerFrameCompositionState() {
+ Layer::preparePerFrameCompositionState();
- compositionState.color = getColor();
- compositionState.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
+ auto* compositionState = editCompositionState();
+ compositionState->color = getColor();
+ compositionState->compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
}
-std::shared_ptr<compositionengine::Layer> ColorLayer::getCompositionLayer() const {
- return mCompositionLayer;
+sp<compositionengine::LayerFE> ColorLayer::getCompositionEngineLayerFE() const {
+ return asLayerFE();
+}
+
+compositionengine::LayerFECompositionState* ColorLayer::editCompositionState() {
+ return mCompositionState.get();
+}
+
+const compositionengine::LayerFECompositionState* ColorLayer::getCompositionState() const {
+ return mCompositionState.get();
}
bool ColorLayer::isOpaque(const Layer::State& s) const {
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index 9246eb2..4deb162 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -28,7 +28,8 @@
explicit ColorLayer(const LayerCreationArgs&);
~ColorLayer() override;
- std::shared_ptr<compositionengine::Layer> getCompositionLayer() const override;
+ sp<compositionengine::LayerFE> getCompositionEngineLayerFE() const override;
+ compositionengine::LayerFECompositionState* editCompositionState() override;
const char* getType() const override { return "ColorLayer"; }
bool isVisible() const override;
@@ -45,11 +46,12 @@
/*
* compositionengine::LayerFE overrides
*/
- void latchPerFrameState(compositionengine::LayerFECompositionState&) const override;
+ const compositionengine::LayerFECompositionState* getCompositionState() const override;
+ void preparePerFrameCompositionState() override;
std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition(
compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
- std::shared_ptr<compositionengine::Layer> mCompositionLayer;
+ std::unique_ptr<compositionengine::LayerFECompositionState> mCompositionState;
sp<Layer> createClone() override;
};
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index a634f2f..2792290 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -51,7 +51,6 @@
"src/DisplaySurface.cpp",
"src/DumpHelpers.cpp",
"src/HwcBufferCache.cpp",
- "src/Layer.cpp",
"src/LayerFECompositionState.cpp",
"src/Output.cpp",
"src/OutputCompositionState.cpp",
@@ -71,7 +70,6 @@
"mock/Display.cpp",
"mock/DisplayColorProfile.cpp",
"mock/DisplaySurface.cpp",
- "mock/Layer.cpp",
"mock/LayerFE.cpp",
"mock/NativeWindow.cpp",
"mock/Output.cpp",
@@ -96,7 +94,6 @@
"tests/DisplayColorProfileTest.cpp",
"tests/DisplayTest.cpp",
"tests/HwcBufferCacheTest.cpp",
- "tests/LayerTest.cpp",
"tests/MockHWC2.cpp",
"tests/MockHWComposer.cpp",
"tests/MockPowerAdvisor.cpp",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
index e3650f3..3faa068 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
@@ -32,11 +32,11 @@
namespace compositionengine {
class Display;
-class Layer;
struct CompositionRefreshArgs;
struct DisplayCreationArgs;
struct LayerCreationArgs;
+struct LayerFECompositionState;
/**
* Encapsulates all the interfaces and implementation details for performing
@@ -48,7 +48,8 @@
// Create a composition Display
virtual std::shared_ptr<Display> createDisplay(const DisplayCreationArgs&) = 0;
- virtual std::shared_ptr<Layer> createLayer(const LayerCreationArgs&) = 0;
+ virtual std::unique_ptr<compositionengine::LayerFECompositionState>
+ createLayerFECompositionState() = 0;
virtual HWComposer& getHwComposer() const = 0;
virtual void setHwComposer(std::unique_ptr<HWComposer>) = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
index 90158c7..4a0d6ee 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
@@ -21,15 +21,14 @@
#include <vector>
#include <compositionengine/Display.h>
-#include <compositionengine/Layer.h>
+#include <compositionengine/LayerFE.h>
#include <compositionengine/OutputColorSetting.h>
#include <math/mat4.h>
namespace android::compositionengine {
-using Layers = std::vector<std::shared_ptr<compositionengine::Layer>>;
+using Layers = std::vector<sp<compositionengine::LayerFE>>;
using Outputs = std::vector<std::shared_ptr<compositionengine::Output>>;
-using RawLayers = std::vector<compositionengine::Layer*>;
/**
* A parameter object for refreshing a set of outputs
@@ -44,7 +43,7 @@
Layers layers;
// All the layers that have queued updates.
- RawLayers layersWithQueuedFrames;
+ Layers layersWithQueuedFrames;
// If true, forces the entire display to be considered dirty and repainted
bool repaintEverything{false};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h
deleted file mode 100644
index 1259c52..0000000
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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 <cstdint>
-#include <string>
-
-#include <utils/StrongPointer.h>
-
-namespace android::compositionengine {
-
-class Display;
-class LayerFE;
-
-struct LayerFECompositionState;
-
-/**
- * A layer contains the output-independent composition state for a front-end
- * Layer
- */
-class Layer {
-public:
- virtual ~Layer();
-
- // Gets the front-end interface for this layer. Can return nullptr if the
- // front-end layer no longer exists.
- virtual sp<LayerFE> getLayerFE() const = 0;
-
- // Gets the raw front-end composition state data for the layer
- // TODO(lpique): Make this protected once it is only internally called.
- virtual const LayerFECompositionState& getFEState() const = 0;
-
- // Allows mutable access to the raw front-end composition state
- // TODO(lpique): Make this protected once it is only internally called.
- virtual LayerFECompositionState& editFEState() = 0;
-
- // Debugging
- virtual void dump(std::string& result) const = 0;
-};
-
-} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerCreationArgs.h
deleted file mode 100644
index db3312b..0000000
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerCreationArgs.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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 <utils/RefBase.h>
-
-namespace android::compositionengine {
-
-class CompositionEngine;
-class LayerFE;
-
-/**
- * A parameter object for creating Layer instances
- */
-struct LayerCreationArgs {
- // A weak pointer to the front-end layer instance that the new layer will
- // represent.
- wp<LayerFE> layerFE;
-};
-
-} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index 26442d9..912dffd 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -44,6 +44,9 @@
// of the front-end layer
class LayerFE : public virtual RefBase {
public:
+ // Gets the raw front-end composition state data for the layer
+ virtual const LayerFECompositionState* getCompositionState() const = 0;
+
// Called before composition starts. Should return true if this layer has
// pending updates which would require an extra display refresh cycle to
// process.
@@ -60,19 +63,18 @@
// content (buffer or color) state for the layer.
GeometryAndContent,
- // Gets the per frame content (buffer or color) state the layer.
+ // Gets the per frame content (buffer or color) state for the layer.
Content,
+
+ // Gets the cursor state for the layer.
+ Cursor,
};
- // Latches the output-independent composition state for the layer. The
+ // Prepares the output-independent composition state for the layer. The
// StateSubset argument selects what portion of the state is actually needed
// by the CompositionEngine code, since computing everything may be
// expensive.
- virtual void latchCompositionState(LayerFECompositionState&, StateSubset) const = 0;
-
- // Latches the minimal bit of state for the cursor for a fast asynchronous
- // update.
- virtual void latchCursorCompositionState(LayerFECompositionState&) const = 0;
+ virtual void prepareCompositionState(StateSubset) = 0;
struct ClientCompositionTargetSettings {
// The clip region, or visible region that is being rendered to
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index 1af99c5..40cd3e0 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -162,8 +162,10 @@
// The output-independent frame for the cursor
Rect cursorFrame;
+ virtual ~LayerFECompositionState();
+
// Debugging
- void dump(std::string& out) const;
+ virtual void dump(std::string& out) const;
};
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 4ab7082..9622e78 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -41,7 +41,6 @@
namespace android::compositionengine {
class DisplayColorProfile;
-class Layer;
class LayerFE;
class RenderSurface;
class OutputLayer;
@@ -216,18 +215,17 @@
virtual bool belongsInOutput(std::optional<uint32_t> layerStackId, bool internalOnly) const = 0;
// Determines if a layer belongs to the output.
- virtual bool belongsInOutput(const Layer*) const = 0;
+ virtual bool belongsInOutput(const sp<LayerFE>&) const = 0;
// Returns a pointer to the output layer corresponding to the given layer on
// this output, or nullptr if the layer does not have one
- virtual OutputLayer* getOutputLayerForLayer(Layer*) const = 0;
+ virtual OutputLayer* getOutputLayerForLayer(const sp<LayerFE>&) const = 0;
// Immediately clears all layers from the output.
virtual void clearOutputLayers() = 0;
// For tests use only. Creates and appends an OutputLayer into the output.
- virtual OutputLayer* injectOutputLayerForTest(const std::shared_ptr<Layer>&,
- const sp<LayerFE>&) = 0;
+ virtual OutputLayer* injectOutputLayerForTest(const sp<LayerFE>&) = 0;
// Gets the count of output layers managed by this output
virtual size_t getOutputLayerCount() const = 0;
@@ -257,7 +255,7 @@
virtual void rebuildLayerStacks(const CompositionRefreshArgs&, LayerFESet&) = 0;
virtual void collectVisibleLayers(const CompositionRefreshArgs&, CoverageState&) = 0;
- virtual void ensureOutputLayerIfVisible(std::shared_ptr<Layer>, CoverageState&) = 0;
+ virtual void ensureOutputLayerIfVisible(sp<LayerFE>&, CoverageState&) = 0;
virtual void setReleasedLayers(const CompositionRefreshArgs&) = 0;
virtual void updateAndWriteCompositionState(const CompositionRefreshArgs&) = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
index a466561..007b0e8 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
@@ -41,7 +41,6 @@
class CompositionEngine;
class Output;
-class Layer;
class LayerFE;
namespace impl {
@@ -61,9 +60,6 @@
// Gets the output which owns this output layer
virtual const Output& getOutput() const = 0;
- // Gets the display-independent layer which this output layer represents
- virtual Layer& getLayer() const = 0;
-
// Gets the front-end layer interface this output layer represents
virtual LayerFE& getLayerFE() const = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
index 450b9ca..386808d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
@@ -27,8 +27,8 @@
std::shared_ptr<compositionengine::Display> createDisplay(
const compositionengine::DisplayCreationArgs&) override;
- std::shared_ptr<compositionengine::Layer> createLayer(
- const compositionengine::LayerCreationArgs&) override;
+ std::unique_ptr<compositionengine::LayerFECompositionState> createLayerFECompositionState()
+ override;
HWComposer& getHwComposer() const override;
void setHwComposer(std::unique_ptr<HWComposer>) override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index 39acb37..fb597ce 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -73,8 +73,7 @@
virtual void applyLayerRequestsToLayers(const LayerRequests&);
// Internal
- std::unique_ptr<compositionengine::OutputLayer> createOutputLayer(
- const std::shared_ptr<compositionengine::Layer>&, const sp<LayerFE>&) const;
+ std::unique_ptr<compositionengine::OutputLayer> createOutputLayer(const sp<LayerFE>&) const;
private:
const bool mIsVirtual;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Layer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Layer.h
deleted file mode 100644
index 46489fb..0000000
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Layer.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * 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 <memory>
-
-#include <compositionengine/Layer.h>
-#include <compositionengine/LayerCreationArgs.h>
-#include <utils/StrongPointer.h>
-
-namespace android::compositionengine {
-
-struct LayerCreationArgs;
-
-namespace impl {
-
-// The implementation class contains the common implementation, but does not
-// actually contain the final layer state.
-class Layer : public virtual compositionengine::Layer {
-public:
- ~Layer() override;
-
- // compositionengine::Layer overrides
- void dump(std::string&) const override;
-
-protected:
- // Implemented by the final implementation for the final state it uses.
- virtual void dumpFEState(std::string&) const = 0;
-};
-
-// This template factory function standardizes the implementation details of the
-// final class using the types actually required by the implementation. This is
-// not possible to do in the base class as those types may not even be visible
-// to the base code.
-template <typename BaseLayer, typename LayerCreationArgs>
-std::shared_ptr<BaseLayer> createLayerTemplated(const LayerCreationArgs& args) {
- class Layer final : public BaseLayer {
- public:
-// Clang incorrectly complains that these are unused.
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunused-local-typedef"
- using LayerFE = std::remove_pointer_t<decltype(
- std::declval<decltype(std::declval<LayerCreationArgs>().layerFE)>().unsafe_get())>;
- using LayerFECompositionState = std::remove_const_t<
- std::remove_reference_t<decltype(std::declval<BaseLayer>().getFEState())>>;
-#pragma clang diagnostic pop
-
- explicit Layer(const LayerCreationArgs& args) : mLayerFE(args.layerFE) {}
- ~Layer() override = default;
-
- private:
- // compositionengine::Layer overrides
- sp<compositionengine::LayerFE> getLayerFE() const override { return mLayerFE.promote(); }
- const LayerFECompositionState& getFEState() const override { return mFrontEndState; }
- LayerFECompositionState& editFEState() override { return mFrontEndState; }
-
- // compositionengine::impl::Layer overrides
- void dumpFEState(std::string& out) const override { mFrontEndState.dump(out); }
-
- const wp<LayerFE> mLayerFE;
- LayerFECompositionState mFrontEndState;
- };
-
- return std::make_shared<Layer>(args);
-}
-
-std::shared_ptr<Layer> createLayer(const LayerCreationArgs&);
-
-} // namespace impl
-} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 8dc440c..d41337c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -60,10 +60,9 @@
Region getDirtyRegion(bool repaintEverything) const override;
bool belongsInOutput(std::optional<uint32_t>, bool) const override;
- bool belongsInOutput(const compositionengine::Layer*) const override;
+ bool belongsInOutput(const sp<LayerFE>&) const override;
- compositionengine::OutputLayer* getOutputLayerForLayer(
- compositionengine::Layer*) const override;
+ compositionengine::OutputLayer* getOutputLayerForLayer(const sp<LayerFE>&) const override;
void setReleasedLayers(ReleasedLayers&&) override;
@@ -73,7 +72,7 @@
void rebuildLayerStacks(const CompositionRefreshArgs&, LayerFESet&) override;
void collectVisibleLayers(const CompositionRefreshArgs&,
compositionengine::Output::CoverageState&) override;
- void ensureOutputLayerIfVisible(std::shared_ptr<compositionengine::Layer>,
+ void ensureOutputLayerIfVisible(sp<compositionengine::LayerFE>&,
compositionengine::Output::CoverageState&) override;
void setReleasedLayers(const compositionengine::CompositionRefreshArgs&) override;
@@ -94,9 +93,9 @@
void setRenderSurfaceForTest(std::unique_ptr<compositionengine::RenderSurface>);
protected:
- std::unique_ptr<compositionengine::OutputLayer> createOutputLayer(
- const std::shared_ptr<compositionengine::Layer>&, const sp<LayerFE>&) const;
- std::optional<size_t> findCurrentOutputLayerForLayer(compositionengine::Layer*) const;
+ std::unique_ptr<compositionengine::OutputLayer> createOutputLayer(const sp<LayerFE>&) const;
+ std::optional<size_t> findCurrentOutputLayerForLayer(
+ const sp<compositionengine::LayerFE>&) const;
void chooseCompositionStrategy() override;
bool getSkipColorTransform() const override;
compositionengine::Output::FrameFences presentAndGetFrameFences() override;
@@ -108,11 +107,9 @@
void dumpBase(std::string&) const;
// Implemented by the final implementation for the final state it uses.
- virtual compositionengine::OutputLayer* ensureOutputLayer(
- std::optional<size_t>, const std::shared_ptr<compositionengine::Layer>&,
- const sp<LayerFE>&) = 0;
- virtual compositionengine::OutputLayer* injectOutputLayerForTest(
- const std::shared_ptr<compositionengine::Layer>&, const sp<LayerFE>&) = 0;
+ virtual compositionengine::OutputLayer* ensureOutputLayer(std::optional<size_t>,
+ const sp<LayerFE>&) = 0;
+ virtual compositionengine::OutputLayer* injectOutputLayerForTest(const sp<LayerFE>&) = 0;
virtual void finalizePendingOutputLayers() = 0;
virtual const compositionengine::CompositionEngine& getCompositionEngine() const = 0;
virtual void dumpState(std::string& out) const = 0;
@@ -181,11 +178,10 @@
};
OutputLayer* ensureOutputLayer(std::optional<size_t> prevIndex,
- const std::shared_ptr<compositionengine::Layer>& layer,
const sp<LayerFE>& layerFE) {
auto outputLayer = (prevIndex && *prevIndex <= mCurrentOutputLayersOrderedByZ.size())
? std::move(mCurrentOutputLayersOrderedByZ[*prevIndex])
- : BaseOutput::createOutputLayer(layer, layerFE);
+ : BaseOutput::createOutputLayer(layerFE);
auto result = outputLayer.get();
mPendingOutputLayersOrderedByZ.emplace_back(std::move(outputLayer));
return result;
@@ -202,10 +198,8 @@
void dumpState(std::string& out) const override { mState.dump(out); }
- OutputLayer* injectOutputLayerForTest(
- const std::shared_ptr<compositionengine::Layer>& layer,
- const sp<LayerFE>& layerFE) override {
- auto outputLayer = BaseOutput::createOutputLayer(layer, layerFE);
+ OutputLayer* injectOutputLayerForTest(const sp<LayerFE>& layerFE) override {
+ auto outputLayer = BaseOutput::createOutputLayer(layerFE);
auto result = outputLayer.get();
mCurrentOutputLayersOrderedByZ.emplace_back(std::move(outputLayer));
return result;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index 95c8afb..79df9b2 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -81,7 +81,6 @@
// to the base code.
template <typename BaseOutputLayer>
std::unique_ptr<BaseOutputLayer> createOutputLayerTemplated(const Output& output,
- std::shared_ptr<Layer> layer,
sp<LayerFE> layerFE) {
class OutputLayer final : public BaseOutputLayer {
public:
@@ -93,21 +92,18 @@
std::remove_reference_t<decltype(std::declval<BaseOutputLayer>().getState())>>;
using Output = std::remove_const_t<
std::remove_reference_t<decltype(std::declval<BaseOutputLayer>().getOutput())>>;
- using Layer = std::remove_reference_t<decltype(std::declval<BaseOutputLayer>().getLayer())>;
using LayerFE =
std::remove_reference_t<decltype(std::declval<BaseOutputLayer>().getLayerFE())>;
#pragma clang diagnostic pop
- OutputLayer(const Output& output, const std::shared_ptr<Layer>& layer,
- const sp<LayerFE>& layerFE)
- : mOutput(output), mLayer(layer), mLayerFE(layerFE) {}
+ OutputLayer(const Output& output, const sp<LayerFE>& layerFE)
+ : mOutput(output), mLayerFE(layerFE) {}
~OutputLayer() override = default;
private:
// compositionengine::OutputLayer overrides
const Output& getOutput() const override { return mOutput; }
- Layer& getLayer() const override { return *mLayer; }
LayerFE& getLayerFE() const override { return *mLayerFE; }
const OutputLayerCompositionState& getState() const override { return mState; }
OutputLayerCompositionState& editState() override { return mState; }
@@ -116,16 +112,14 @@
void dumpState(std::string& out) const override { mState.dump(out); }
const Output& mOutput;
- const std::shared_ptr<Layer> mLayer;
const sp<LayerFE> mLayerFE;
OutputLayerCompositionState mState;
};
- return std::make_unique<OutputLayer>(output, layer, layerFE);
+ return std::make_unique<OutputLayer>(output, layerFE);
}
std::unique_ptr<OutputLayer> createOutputLayer(const compositionengine::Output&,
- const std::shared_ptr<compositionengine::Layer>&,
const sp<LayerFE>&);
} // namespace impl
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
index 104e20d..f953d0b 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
@@ -19,7 +19,7 @@
#include <compositionengine/CompositionEngine.h>
#include <compositionengine/CompositionRefreshArgs.h>
#include <compositionengine/DisplayCreationArgs.h>
-#include <compositionengine/LayerCreationArgs.h>
+#include <compositionengine/LayerFECompositionState.h>
#include <gmock/gmock.h>
#include <renderengine/RenderEngine.h>
@@ -33,7 +33,8 @@
~CompositionEngine() override;
MOCK_METHOD1(createDisplay, std::shared_ptr<Display>(const DisplayCreationArgs&));
- MOCK_METHOD1(createLayer, std::shared_ptr<Layer>(const LayerCreationArgs&));
+ MOCK_METHOD0(createLayerFECompositionState,
+ std::unique_ptr<compositionengine::LayerFECompositionState>());
MOCK_CONST_METHOD0(getHwComposer, HWComposer&());
MOCK_METHOD1(setHwComposer, void(std::unique_ptr<HWComposer>));
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Layer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Layer.h
deleted file mode 100644
index 4f03cb4..0000000
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Layer.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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 <compositionengine/Layer.h>
-#include <compositionengine/LayerFE.h>
-#include <compositionengine/LayerFECompositionState.h>
-#include <gmock/gmock.h>
-
-namespace android::compositionengine::mock {
-
-class Layer : public compositionengine::Layer {
-public:
- Layer();
- virtual ~Layer();
-
- MOCK_CONST_METHOD0(getLayerFE, sp<LayerFE>());
-
- MOCK_CONST_METHOD0(getFEState, const LayerFECompositionState&());
- MOCK_METHOD0(editFEState, LayerFECompositionState&());
-
- MOCK_CONST_METHOD1(dump, void(std::string&));
-};
-
-} // 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 163e302..5c2ad15 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -30,11 +30,11 @@
LayerFE();
virtual ~LayerFE();
+ MOCK_CONST_METHOD0(getCompositionState, const LayerFECompositionState*());
+
MOCK_METHOD1(onPreComposition, bool(nsecs_t));
- MOCK_CONST_METHOD2(latchCompositionState,
- void(LayerFECompositionState&, compositionengine::LayerFE::StateSubset));
- MOCK_CONST_METHOD1(latchCursorCompositionState, void(LayerFECompositionState&));
+ MOCK_METHOD1(prepareCompositionState, void(compositionengine::LayerFE::StateSubset));
MOCK_METHOD1(prepareClientComposition,
std::optional<LayerSettings>(
compositionengine::LayerFE::ClientCompositionTargetSettings&));
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index 59906b9..346c2d1 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -18,7 +18,6 @@
#include <compositionengine/CompositionRefreshArgs.h>
#include <compositionengine/DisplayColorProfile.h>
-#include <compositionengine/Layer.h>
#include <compositionengine/LayerFE.h>
#include <compositionengine/Output.h>
#include <compositionengine/OutputLayer.h>
@@ -62,14 +61,13 @@
MOCK_CONST_METHOD1(getDirtyRegion, Region(bool));
MOCK_CONST_METHOD2(belongsInOutput, bool(std::optional<uint32_t>, bool));
- MOCK_CONST_METHOD1(belongsInOutput, bool(const compositionengine::Layer*));
+ MOCK_CONST_METHOD1(belongsInOutput, bool(const sp<compositionengine::LayerFE>&));
MOCK_CONST_METHOD1(getOutputLayerForLayer,
- compositionengine::OutputLayer*(compositionengine::Layer*));
+ compositionengine::OutputLayer*(const sp<compositionengine::LayerFE>&));
MOCK_METHOD0(clearOutputLayers, void());
- MOCK_METHOD2(injectOutputLayerForTest,
- compositionengine::OutputLayer*(const std::shared_ptr<compositionengine::Layer>&,
- const sp<compositionengine::LayerFE>&));
+ MOCK_METHOD1(injectOutputLayerForTest,
+ compositionengine::OutputLayer*(const sp<compositionengine::LayerFE>&));
MOCK_CONST_METHOD0(getOutputLayerCount, size_t());
MOCK_CONST_METHOD1(getOutputLayerOrderedByZByIndex, OutputLayer*(size_t));
@@ -84,8 +82,7 @@
void(const compositionengine::CompositionRefreshArgs&,
compositionengine::Output::CoverageState&));
MOCK_METHOD2(ensureOutputLayerIfVisible,
- void(std::shared_ptr<compositionengine::Layer>,
- compositionengine::Output::CoverageState&));
+ void(sp<compositionengine::LayerFE>&, compositionengine::Output::CoverageState&));
MOCK_METHOD1(setReleasedLayers, void(const compositionengine::CompositionRefreshArgs&));
MOCK_CONST_METHOD1(updateLayerStateFromFE, void(const CompositionRefreshArgs&));
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
index 631760a..2ecbad8 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
@@ -17,7 +17,6 @@
#pragma once
#include <compositionengine/CompositionEngine.h>
-#include <compositionengine/Layer.h>
#include <compositionengine/LayerFE.h>
#include <compositionengine/Output.h>
#include <compositionengine/OutputLayer.h>
@@ -34,7 +33,6 @@
MOCK_METHOD1(setHwcLayer, void(std::shared_ptr<HWC2::Layer>));
MOCK_CONST_METHOD0(getOutput, const compositionengine::Output&());
- MOCK_CONST_METHOD0(getLayer, compositionengine::Layer&());
MOCK_CONST_METHOD0(getLayerFE, compositionengine::LayerFE&());
MOCK_CONST_METHOD0(getState, const impl::OutputLayerCompositionState&());
diff --git a/services/surfaceflinger/CompositionEngine/mock/Layer.cpp b/services/surfaceflinger/CompositionEngine/mock/Layer.cpp
deleted file mode 100644
index 08483cb..0000000
--- a/services/surfaceflinger/CompositionEngine/mock/Layer.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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 <compositionengine/mock/Layer.h>
-
-namespace android::compositionengine::mock {
-
-// The Google Mock documentation recommends explicit non-header instantiations
-// for better compile time performance.
-Layer::Layer() = default;
-Layer::~Layer() = default;
-
-} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
index aeaa18a..6203dc6 100644
--- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
@@ -16,10 +16,10 @@
#include <compositionengine/CompositionRefreshArgs.h>
#include <compositionengine/LayerFE.h>
+#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/OutputLayer.h>
#include <compositionengine/impl/CompositionEngine.h>
#include <compositionengine/impl/Display.h>
-#include <compositionengine/impl/Layer.h>
#include <renderengine/RenderEngine.h>
#include <utils/Trace.h>
@@ -51,9 +51,9 @@
return compositionengine::impl::createDisplay(*this, args);
}
-std::shared_ptr<compositionengine::Layer> CompositionEngine::createLayer(
- const LayerCreationArgs& args) {
- return compositionengine::impl::createLayer(args);
+std::unique_ptr<compositionengine::LayerFECompositionState>
+CompositionEngine::createLayerFECompositionState() {
+ return std::make_unique<compositionengine::LayerFECompositionState>();
}
HWComposer& CompositionEngine::getHwComposer() const {
@@ -120,8 +120,7 @@
for (auto* layer : output->getOutputLayersOrderedByZ()) {
if (layer->isHardwareCursor()) {
// Latch the cursor composition state from each front-end layer.
- layer->getLayerFE().latchCursorCompositionState(layer->getLayer().editFEState());
-
+ layer->getLayerFE().prepareCompositionState(LayerFE::StateSubset::Cursor);
layer->writeCursorPositionToHWC();
}
}
@@ -137,8 +136,7 @@
mRefreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
for (auto& layer : args.layers) {
- sp<compositionengine::LayerFE> layerFE = layer->getLayerFE();
- if (layerFE && layerFE->onPreComposition(mRefreshStartTime)) {
+ if (layer->onPreComposition(mRefreshStartTime)) {
needsAnotherUpdate = true;
}
}
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index ccd6572..1d8a23f 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -147,9 +147,8 @@
}
std::unique_ptr<compositionengine::OutputLayer> Display::createOutputLayer(
- const std::shared_ptr<compositionengine::Layer>& layer,
const sp<compositionengine::LayerFE>& layerFE) const {
- auto result = impl::createOutputLayer(*this, layer, layerFE);
+ auto result = impl::createOutputLayer(*this, layerFE);
if (result && mId) {
auto& hwc = getCompositionEngine().getHwComposer();
@@ -184,16 +183,18 @@
// Any non-null entries in the current list of layers are layers that are no
// longer going to be visible
- for (auto* layer : getOutputLayersOrderedByZ()) {
- if (!layer) {
+ for (auto* outputLayer : getOutputLayersOrderedByZ()) {
+ if (!outputLayer) {
continue;
}
- sp<compositionengine::LayerFE> layerFE(&layer->getLayerFE());
+ compositionengine::LayerFE* layerFE = &outputLayer->getLayerFE();
const bool hasQueuedFrames =
- std::find(refreshArgs.layersWithQueuedFrames.cbegin(),
- refreshArgs.layersWithQueuedFrames.cend(),
- &layer->getLayer()) != refreshArgs.layersWithQueuedFrames.cend();
+ std::any_of(refreshArgs.layersWithQueuedFrames.cbegin(),
+ refreshArgs.layersWithQueuedFrames.cend(),
+ [layerFE](sp<compositionengine::LayerFE> layerWithQueuedFrames) {
+ return layerFE == layerWithQueuedFrames.get();
+ });
if (hasQueuedFrames) {
releasedLayers.emplace_back(layerFE);
diff --git a/services/surfaceflinger/CompositionEngine/src/Layer.cpp b/services/surfaceflinger/CompositionEngine/src/Layer.cpp
deleted file mode 100644
index ecacaee..0000000
--- a/services/surfaceflinger/CompositionEngine/src/Layer.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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 <android-base/stringprintf.h>
-#include <compositionengine/LayerFE.h>
-#include <compositionengine/LayerFECompositionState.h>
-#include <compositionengine/impl/Layer.h>
-
-namespace android::compositionengine {
-
-Layer::~Layer() = default;
-
-namespace impl {
-
-std::shared_ptr<Layer> createLayer(const LayerCreationArgs& args) {
- return compositionengine::impl::createLayerTemplated<Layer>(args);
-}
-
-Layer::~Layer() = default;
-
-void Layer::dump(std::string& out) const {
- auto layerFE = getLayerFE();
- android::base::StringAppendF(&out, "* compositionengine::Layer %p (%s)\n", this,
- layerFE ? layerFE->getDebugName() : "<unknown>");
- out.append(" frontend:\n");
- dumpFEState(out);
-}
-
-} // namespace impl
-} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
index 016084f..3e0f803 100644
--- a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
@@ -32,6 +32,8 @@
} // namespace
+LayerFECompositionState::~LayerFECompositionState() = default;
+
void LayerFECompositionState::dump(std::string& out) const {
out.append(" ");
dumpVal(out, "isSecure", isSecure);
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index ce4b84a..a389bf3 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -20,7 +20,6 @@
#include <compositionengine/CompositionEngine.h>
#include <compositionengine/CompositionRefreshArgs.h>
#include <compositionengine/DisplayColorProfile.h>
-#include <compositionengine/Layer.h>
#include <compositionengine/LayerFE.h>
#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/RenderSurface.h>
@@ -267,31 +266,26 @@
(!internalOnly || outputState.layerStackInternal);
}
-bool Output::belongsInOutput(const compositionengine::Layer* layer) const {
- if (!layer) {
- return false;
- }
-
- const auto& layerFEState = layer->getFEState();
- return belongsInOutput(layerFEState.layerStackId, layerFEState.internalOnly);
+bool Output::belongsInOutput(const sp<compositionengine::LayerFE>& layerFE) const {
+ const auto* layerFEState = layerFE->getCompositionState();
+ return layerFEState && belongsInOutput(layerFEState->layerStackId, layerFEState->internalOnly);
}
std::unique_ptr<compositionengine::OutputLayer> Output::createOutputLayer(
- const std::shared_ptr<compositionengine::Layer>& layer, const sp<LayerFE>& layerFE) const {
- return impl::createOutputLayer(*this, layer, layerFE);
+ const sp<LayerFE>& layerFE) const {
+ return impl::createOutputLayer(*this, layerFE);
}
-compositionengine::OutputLayer* Output::getOutputLayerForLayer(
- compositionengine::Layer* layer) const {
- auto index = findCurrentOutputLayerForLayer(layer);
+compositionengine::OutputLayer* Output::getOutputLayerForLayer(const sp<LayerFE>& layerFE) const {
+ auto index = findCurrentOutputLayerForLayer(layerFE);
return index ? getOutputLayerOrderedByZByIndex(*index) : nullptr;
}
std::optional<size_t> Output::findCurrentOutputLayerForLayer(
- compositionengine::Layer* layer) const {
+ const sp<compositionengine::LayerFE>& layer) const {
for (size_t i = 0; i < getOutputLayerCount(); i++) {
auto outputLayer = getOutputLayerOrderedByZByIndex(i);
- if (outputLayer && &outputLayer->getLayer() == layer) {
+ if (outputLayer && &outputLayer->getLayerFE() == layer.get()) {
return i;
}
}
@@ -354,7 +348,7 @@
// Evaluate the layers from front to back to determine what is visible. This
// also incrementally calculates the coverage information for each layer as
// well as the entire output.
- for (auto& layer : reversed(refreshArgs.layers)) {
+ for (auto layer : reversed(refreshArgs.layers)) {
// Incrementally process the coverage for each layer
ensureOutputLayerIfVisible(layer, coverage);
@@ -373,28 +367,29 @@
}
}
-void Output::ensureOutputLayerIfVisible(std::shared_ptr<compositionengine::Layer> layer,
+void Output::ensureOutputLayerIfVisible(sp<compositionengine::LayerFE>& layerFE,
compositionengine::Output::CoverageState& coverage) {
- // Note: Converts a wp<LayerFE> to a sp<LayerFE>
- auto layerFE = layer->getLayerFE();
- if (layerFE == nullptr) {
- return;
- }
-
// Ensure we have a snapshot of the basic geometry layer state. Limit the
// snapshots to once per frame for each candidate layer, as layers may
// appear on multiple outputs.
if (!coverage.latchedLayers.count(layerFE)) {
coverage.latchedLayers.insert(layerFE);
- layerFE->latchCompositionState(layer->editFEState(),
- compositionengine::LayerFE::StateSubset::BasicGeometry);
+ layerFE->prepareCompositionState(compositionengine::LayerFE::StateSubset::BasicGeometry);
}
- // Obtain a read-only reference to the front-end layer state
- const auto& layerFEState = layer->getFEState();
-
// Only consider the layers on the given layer stack
- if (!belongsInOutput(layer.get())) {
+ if (!belongsInOutput(layerFE)) {
+ return;
+ }
+
+ // Obtain a read-only pointer to the front-end layer state
+ const auto* layerFEState = layerFE->getCompositionState();
+ if (CC_UNLIKELY(!layerFEState)) {
+ return;
+ }
+
+ // handle hidden surfaces by setting the visible region to empty
+ if (CC_UNLIKELY(!layerFEState->isVisible)) {
return;
}
@@ -432,23 +427,18 @@
*/
Region shadowRegion;
- // handle hidden surfaces by setting the visible region to empty
- if (CC_UNLIKELY(!layerFEState.isVisible)) {
- return;
- }
-
- const ui::Transform& tr = layerFEState.geomLayerTransform;
+ const ui::Transform& tr = layerFEState->geomLayerTransform;
// Get the visible region
// TODO(b/121291683): Is it worth creating helper methods on LayerFEState
// for computations like this?
- const Rect visibleRect(tr.transform(layerFEState.geomLayerBounds));
+ const Rect visibleRect(tr.transform(layerFEState->geomLayerBounds));
visibleRegion.set(visibleRect);
- if (layerFEState.shadowRadius > 0.0f) {
+ if (layerFEState->shadowRadius > 0.0f) {
// if the layer casts a shadow, offset the layers visible region and
// calculate the shadow region.
- const auto inset = static_cast<int32_t>(ceilf(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);
@@ -460,10 +450,10 @@
}
// Remove the transparent area from the visible region
- if (!layerFEState.isOpaque) {
+ if (!layerFEState->isOpaque) {
if (tr.preserveRects()) {
// transform the transparent region
- transparentRegion = tr.transform(layerFEState.transparentRegionHint);
+ transparentRegion = tr.transform(layerFEState->transparentRegionHint);
} else {
// transformation too complex, can't do the
// transparent region optimization.
@@ -473,7 +463,7 @@
// compute the opaque region
const auto layerOrientation = tr.getOrientation();
- if (layerFEState.isOpaque && ((layerOrientation & ui::Transform::ROT_INVALID) == 0)) {
+ 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.
// Otherwise we don't try and compute the opaque region since there may
@@ -497,7 +487,7 @@
// Get coverage information for the layer as previously displayed,
// also taking over ownership from mOutputLayersorderedByZ.
- auto prevOutputLayerIndex = findCurrentOutputLayerForLayer(layer.get());
+ auto prevOutputLayerIndex = findCurrentOutputLayerForLayer(layerFE);
auto prevOutputLayer =
prevOutputLayerIndex ? getOutputLayerOrderedByZByIndex(*prevOutputLayerIndex) : nullptr;
@@ -511,7 +501,7 @@
// compute this layer's dirty region
Region dirty;
- if (layerFEState.contentDirty) {
+ if (layerFEState->contentDirty) {
// we need to invalidate the whole region
dirty = visibleRegion;
// as well, as the old visible region
@@ -558,7 +548,7 @@
// The layer is visible. Either reuse the existing outputLayer if we have
// one, or create a new one if we do not.
- auto result = ensureOutputLayer(prevOutputLayerIndex, layer, layerFE);
+ auto result = ensureOutputLayer(prevOutputLayerIndex, layerFE);
// Store the layer coverage information into the layer state as some of it
// is useful later.
@@ -577,10 +567,9 @@
void Output::updateLayerStateFromFE(const CompositionRefreshArgs& args) const {
for (auto* layer : getOutputLayersOrderedByZ()) {
- layer->getLayerFE().latchCompositionState(layer->getLayer().editFEState(),
- args.updatingGeometryThisFrame
- ? LayerFE::StateSubset::GeometryAndContent
- : LayerFE::StateSubset::Content);
+ layer->getLayerFE().prepareCompositionState(
+ args.updatingGeometryThisFrame ? LayerFE::StateSubset::GeometryAndContent
+ : LayerFE::StateSubset::Content);
}
}
@@ -613,7 +602,7 @@
compositionengine::OutputLayer* Output::findLayerRequestingBackgroundComposition() const {
compositionengine::OutputLayer* layerRequestingBgComposition = nullptr;
for (auto* layer : getOutputLayersOrderedByZ()) {
- if (layer->getLayer().getFEState().backgroundBlurRadius > 0) {
+ if (layer->getLayerFE().getCompositionState()->backgroundBlurRadius > 0) {
layerRequestingBgComposition = layer;
}
}
@@ -639,7 +628,7 @@
*outHdrDataSpace = ui::Dataspace::UNKNOWN;
for (const auto* layer : getOutputLayersOrderedByZ()) {
- switch (layer->getLayer().getFEState().dataspace) {
+ switch (layer->getLayerFE().getCompositionState()->dataspace) {
case ui::Dataspace::V0_SCRGB:
case ui::Dataspace::V0_SCRGB_LINEAR:
case ui::Dataspace::BT2020:
@@ -655,7 +644,8 @@
case ui::Dataspace::BT2020_ITU_PQ:
bestDataSpace = ui::Dataspace::DISPLAY_P3;
*outHdrDataSpace = ui::Dataspace::BT2020_PQ;
- *outIsHdrClientComposition = layer->getLayer().getFEState().forceClientComposition;
+ *outIsHdrClientComposition =
+ layer->getLayerFE().getCompositionState()->forceClientComposition;
break;
case ui::Dataspace::BT2020_HLG:
case ui::Dataspace::BT2020_ITU_HLG:
@@ -867,7 +857,7 @@
if (outputState.isSecure && supportsProtectedContent) {
auto layers = getOutputLayersOrderedByZ();
bool needsProtected = std::any_of(layers.begin(), layers.end(), [](auto* layer) {
- return layer->getLayer().getFEState().hasProtectedContent;
+ return layer->getLayerFE().getCompositionState()->hasProtectedContent;
});
if (needsProtected != renderEngine.isProtected()) {
renderEngine.useProtectedContext(needsProtected);
@@ -955,7 +945,7 @@
for (auto* layer : getOutputLayersOrderedByZ()) {
const auto& layerState = layer->getState();
- const auto& layerFEState = layer->getLayer().getFEState();
+ const auto* layerFEState = layer->getLayerFE().getCompositionState();
auto& layerFE = layer->getLayerFE();
const Region clip(viewportRegion.intersect(layerState.visibleRegion));
@@ -974,7 +964,7 @@
// underneath. We also skip the first layer as the buffer target is
// guaranteed to start out cleared.
bool clearClientComposition =
- layerState.clearClientTarget && layerFEState.isOpaque && !firstLayer;
+ layerState.clearClientTarget && layerFEState->isOpaque && !firstLayer;
ALOGV(" Composition type: client %d clear %d", clientComposition, clearClientComposition);
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index d92b7ef..b538d75 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -16,7 +16,6 @@
#include <android-base/stringprintf.h>
#include <compositionengine/DisplayColorProfile.h>
-#include <compositionengine/Layer.h>
#include <compositionengine/LayerFE.h>
#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/Output.h>
@@ -51,11 +50,9 @@
} // namespace
-std::unique_ptr<OutputLayer> createOutputLayer(
- const compositionengine::Output& output,
- const std::shared_ptr<compositionengine::Layer>& layer,
- const sp<compositionengine::LayerFE>& layerFE) {
- return createOutputLayerTemplated<OutputLayer>(output, layer, layerFE);
+std::unique_ptr<OutputLayer> createOutputLayer(const compositionengine::Output& output,
+ const sp<compositionengine::LayerFE>& layerFE) {
+ return createOutputLayerTemplated<OutputLayer>(output, layerFE);
}
OutputLayer::~OutputLayer() = default;
@@ -70,7 +67,7 @@
}
Rect OutputLayer::calculateInitialCrop() const {
- const auto& layerState = getLayer().getFEState();
+ const auto& layerState = *getLayerFE().getCompositionState();
// apply the projection's clipping to the window crop in
// layerstack space, and convert-back to layer space.
@@ -103,7 +100,7 @@
}
FloatRect OutputLayer::calculateOutputSourceCrop() const {
- const auto& layerState = getLayer().getFEState();
+ const auto& layerState = *getLayerFE().getCompositionState();
const auto& outputState = getOutput().getState();
if (!layerState.geomUsesSourceCrop) {
@@ -180,7 +177,7 @@
}
Rect OutputLayer::calculateOutputDisplayFrame() const {
- const auto& layerState = getLayer().getFEState();
+ const auto& layerState = *getLayerFE().getCompositionState();
const auto& outputState = getOutput().getState();
// apply the layer's transform, followed by the display's global transform
@@ -227,7 +224,7 @@
}
uint32_t OutputLayer::calculateOutputRelativeBufferTransform() const {
- const auto& layerState = getLayer().getFEState();
+ const auto& layerState = *getLayerFE().getCompositionState();
const auto& outputState = getOutput().getState();
/*
@@ -267,7 +264,11 @@
} // namespace impl
void OutputLayer::updateCompositionState(bool includeGeometry, bool forceClientComposition) {
- const auto& layerFEState = getLayer().getFEState();
+ const auto* layerFEState = getLayerFE().getCompositionState();
+ if (!layerFEState) {
+ return;
+ }
+
const auto& outputState = getOutput().getState();
const auto& profile = *getOutput().getDisplayColorProfile();
auto& state = editState();
@@ -285,7 +286,7 @@
state.bufferTransform =
static_cast<Hwc2::Transform>(calculateOutputRelativeBufferTransform());
- if ((layerFEState.isSecure && !outputState.isSecure) ||
+ if ((layerFEState->isSecure && !outputState.isSecure) ||
(state.bufferTransform & ui::Transform::ROT_INVALID)) {
state.forceClientComposition = true;
}
@@ -294,14 +295,14 @@
// Determine the output dependent dataspace for this layer. If it is
// colorspace agnostic, it just uses the dataspace chosen for the output to
// avoid the need for color conversion.
- state.dataspace = layerFEState.isColorspaceAgnostic &&
+ state.dataspace = layerFEState->isColorspaceAgnostic &&
outputState.targetDataspace != ui::Dataspace::UNKNOWN
? outputState.targetDataspace
- : layerFEState.dataspace;
+ : layerFEState->dataspace;
// These are evaluated every frame as they can potentially change at any
// time.
- if (layerFEState.forceClientComposition || !profile.isDataspaceSupported(state.dataspace) ||
+ if (layerFEState->forceClientComposition || !profile.isDataspaceSupported(state.dataspace) ||
forceClientComposition) {
state.forceClientComposition = true;
}
@@ -321,21 +322,25 @@
return;
}
- const auto& outputIndependentState = getLayer().getFEState();
- auto requestedCompositionType = outputIndependentState.compositionType;
+ const auto* outputIndependentState = getLayerFE().getCompositionState();
+ if (!outputIndependentState) {
+ return;
+ }
+
+ auto requestedCompositionType = outputIndependentState->compositionType;
if (includeGeometry) {
writeOutputDependentGeometryStateToHWC(hwcLayer.get(), requestedCompositionType);
- writeOutputIndependentGeometryStateToHWC(hwcLayer.get(), outputIndependentState);
+ writeOutputIndependentGeometryStateToHWC(hwcLayer.get(), *outputIndependentState);
}
writeOutputDependentPerFrameStateToHWC(hwcLayer.get());
- writeOutputIndependentPerFrameStateToHWC(hwcLayer.get(), outputIndependentState);
+ writeOutputIndependentPerFrameStateToHWC(hwcLayer.get(), *outputIndependentState);
writeCompositionTypeToHWC(hwcLayer.get(), requestedCompositionType);
// Always set the layer color after setting the composition type.
- writeSolidColorStateToHWC(hwcLayer.get(), outputIndependentState);
+ writeSolidColorStateToHWC(hwcLayer.get(), *outputIndependentState);
}
void OutputLayer::writeOutputDependentGeometryStateToHWC(
@@ -546,10 +551,14 @@
return;
}
- const auto& layerFEState = getLayer().getFEState();
+ const auto* layerFEState = getLayerFE().getCompositionState();
+ if (!layerFEState) {
+ return;
+ }
+
const auto& outputState = getOutput().getState();
- Rect frame = layerFEState.cursorFrame;
+ Rect frame = layerFEState->cursorFrame;
frame.intersect(outputState.viewport, &frame);
Rect position = outputState.transform.transform(frame);
@@ -646,8 +655,7 @@
void OutputLayer::dump(std::string& out) const {
using android::base::StringAppendF;
- StringAppendF(&out, " - Output Layer %p (Composition layer %p) (%s)\n", this, &getLayer(),
- getLayerFE().getDebugName());
+ StringAppendF(&out, " - Output Layer %p(%s)\n", this, getLayerFE().getDebugName());
dumpState(out);
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
index c1faa90..d889d74 100644
--- a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
@@ -17,7 +17,6 @@
#include <compositionengine/CompositionRefreshArgs.h>
#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/impl/CompositionEngine.h>
-#include <compositionengine/mock/Layer.h>
#include <compositionengine/mock/LayerFE.h>
#include <compositionengine/mock/Output.h>
#include <compositionengine/mock/OutputLayer.h>
@@ -50,11 +49,6 @@
std::shared_ptr<mock::Output> mOutput1{std::make_shared<StrictMock<mock::Output>>()};
std::shared_ptr<mock::Output> mOutput2{std::make_shared<StrictMock<mock::Output>>()};
std::shared_ptr<mock::Output> mOutput3{std::make_shared<StrictMock<mock::Output>>()};
-
- std::shared_ptr<mock::Layer> mLayer1{std::make_shared<StrictMock<mock::Layer>>()};
- std::shared_ptr<mock::Layer> mLayer2{std::make_shared<StrictMock<mock::Layer>>()};
- std::shared_ptr<mock::Layer> mLayer3{std::make_shared<StrictMock<mock::Layer>>()};
- std::shared_ptr<mock::Layer> mLayer4{std::make_shared<StrictMock<mock::Layer>>()};
};
TEST_F(CompositionEngineTest, canInstantiateCompositionEngine) {
@@ -134,48 +128,32 @@
struct CompositionEngineUpdateCursorAsyncTest : public CompositionEngineTest {
public:
+ struct Layer {
+ Layer() { EXPECT_CALL(outputLayer, getLayerFE()).WillRepeatedly(ReturnRef(layerFE)); }
+
+ StrictMock<mock::OutputLayer> outputLayer;
+ StrictMock<mock::LayerFE> layerFE;
+ LayerFECompositionState layerFEState;
+ };
+
CompositionEngineUpdateCursorAsyncTest() {
EXPECT_CALL(*mOutput1, getOutputLayerCount()).WillRepeatedly(Return(0u));
EXPECT_CALL(*mOutput1, getOutputLayerOrderedByZByIndex(_)).Times(0);
EXPECT_CALL(*mOutput2, getOutputLayerCount()).WillRepeatedly(Return(1u));
EXPECT_CALL(*mOutput2, getOutputLayerOrderedByZByIndex(0))
- .WillRepeatedly(Return(&mOutput2OutputLayer1));
+ .WillRepeatedly(Return(&mOutput2Layer1.outputLayer));
EXPECT_CALL(*mOutput3, getOutputLayerCount()).WillRepeatedly(Return(2u));
EXPECT_CALL(*mOutput3, getOutputLayerOrderedByZByIndex(0))
- .WillRepeatedly(Return(&mOutput3OutputLayer1));
+ .WillRepeatedly(Return(&mOutput3Layer1.outputLayer));
EXPECT_CALL(*mOutput3, getOutputLayerOrderedByZByIndex(1))
- .WillRepeatedly(Return(&mOutput3OutputLayer2));
-
- EXPECT_CALL(mOutput2OutputLayer1, getLayerFE()).WillRepeatedly(ReturnRef(mOutput2Layer1FE));
- EXPECT_CALL(mOutput3OutputLayer1, getLayerFE()).WillRepeatedly(ReturnRef(mOutput3Layer1FE));
- EXPECT_CALL(mOutput3OutputLayer2, getLayerFE()).WillRepeatedly(ReturnRef(mOutput3Layer2FE));
-
- EXPECT_CALL(mOutput2OutputLayer1, getLayer()).WillRepeatedly(ReturnRef(mOutput2Layer1));
- EXPECT_CALL(mOutput3OutputLayer1, getLayer()).WillRepeatedly(ReturnRef(mOutput3Layer1));
- EXPECT_CALL(mOutput3OutputLayer2, getLayer()).WillRepeatedly(ReturnRef(mOutput3Layer2));
-
- EXPECT_CALL(mOutput2Layer1, editFEState()).WillRepeatedly(ReturnRef(mOutput2Layer1FEState));
- EXPECT_CALL(mOutput3Layer1, editFEState()).WillRepeatedly(ReturnRef(mOutput3Layer1FEState));
- EXPECT_CALL(mOutput3Layer2, editFEState()).WillRepeatedly(ReturnRef(mOutput3Layer2FEState));
+ .WillRepeatedly(Return(&mOutput3Layer2.outputLayer));
}
- StrictMock<mock::OutputLayer> mOutput2OutputLayer1;
- StrictMock<mock::OutputLayer> mOutput3OutputLayer1;
- StrictMock<mock::OutputLayer> mOutput3OutputLayer2;
-
- StrictMock<mock::LayerFE> mOutput2Layer1FE;
- StrictMock<mock::LayerFE> mOutput3Layer1FE;
- StrictMock<mock::LayerFE> mOutput3Layer2FE;
-
- StrictMock<mock::Layer> mOutput2Layer1;
- StrictMock<mock::Layer> mOutput3Layer1;
- StrictMock<mock::Layer> mOutput3Layer2;
-
- LayerFECompositionState mOutput2Layer1FEState;
- LayerFECompositionState mOutput3Layer1FEState;
- LayerFECompositionState mOutput3Layer2FEState;
+ Layer mOutput2Layer1;
+ Layer mOutput3Layer1;
+ Layer mOutput3Layer2;
};
TEST_F(CompositionEngineUpdateCursorAsyncTest, handlesNoOutputs) {
@@ -183,9 +161,9 @@
}
TEST_F(CompositionEngineUpdateCursorAsyncTest, handlesNoLayersBeingCursorLayers) {
- EXPECT_CALL(mOutput2OutputLayer1, isHardwareCursor()).WillRepeatedly(Return(false));
- EXPECT_CALL(mOutput3OutputLayer1, isHardwareCursor()).WillRepeatedly(Return(false));
- EXPECT_CALL(mOutput3OutputLayer2, isHardwareCursor()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mOutput3Layer1.outputLayer, isHardwareCursor()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mOutput3Layer2.outputLayer, isHardwareCursor()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mOutput2Layer1.outputLayer, isHardwareCursor()).WillRepeatedly(Return(false));
mRefreshArgs.outputs = {mOutput1, mOutput2, mOutput3};
@@ -195,23 +173,23 @@
TEST_F(CompositionEngineUpdateCursorAsyncTest, handlesMultipleLayersBeingCursorLayers) {
{
InSequence seq;
- EXPECT_CALL(mOutput2OutputLayer1, isHardwareCursor()).WillRepeatedly(Return(true));
- EXPECT_CALL(mOutput2Layer1FE, latchCursorCompositionState(Ref(mOutput2Layer1FEState)));
- EXPECT_CALL(mOutput2OutputLayer1, writeCursorPositionToHWC());
+ EXPECT_CALL(mOutput2Layer1.outputLayer, isHardwareCursor()).WillRepeatedly(Return(true));
+ EXPECT_CALL(mOutput2Layer1.layerFE, prepareCompositionState(LayerFE::StateSubset::Cursor));
+ EXPECT_CALL(mOutput2Layer1.outputLayer, writeCursorPositionToHWC());
}
{
InSequence seq;
- EXPECT_CALL(mOutput3OutputLayer1, isHardwareCursor()).WillRepeatedly(Return(true));
- EXPECT_CALL(mOutput3Layer1FE, latchCursorCompositionState(Ref(mOutput3Layer1FEState)));
- EXPECT_CALL(mOutput3OutputLayer1, writeCursorPositionToHWC());
+ EXPECT_CALL(mOutput3Layer1.outputLayer, isHardwareCursor()).WillRepeatedly(Return(true));
+ EXPECT_CALL(mOutput3Layer1.layerFE, prepareCompositionState(LayerFE::StateSubset::Cursor));
+ EXPECT_CALL(mOutput3Layer1.outputLayer, writeCursorPositionToHWC());
}
{
InSequence seq;
- EXPECT_CALL(mOutput3OutputLayer2, isHardwareCursor()).WillRepeatedly(Return(true));
- EXPECT_CALL(mOutput3Layer2FE, latchCursorCompositionState(Ref(mOutput3Layer2FEState)));
- EXPECT_CALL(mOutput3OutputLayer2, writeCursorPositionToHWC());
+ EXPECT_CALL(mOutput3Layer2.outputLayer, isHardwareCursor()).WillRepeatedly(Return(true));
+ EXPECT_CALL(mOutput3Layer2.layerFE, prepareCompositionState(LayerFE::StateSubset::Cursor));
+ EXPECT_CALL(mOutput3Layer2.outputLayer, writeCursorPositionToHWC());
}
mRefreshArgs.outputs = {mOutput1, mOutput2, mOutput3};
@@ -224,14 +202,6 @@
*/
struct CompositionTestPreComposition : public CompositionEngineTest {
- CompositionTestPreComposition() {
- EXPECT_CALL(*mLayer1, getLayerFE()).WillRepeatedly(Return(mLayer1FE));
- EXPECT_CALL(*mLayer2, getLayerFE()).WillRepeatedly(Return(mLayer2FE));
- EXPECT_CALL(*mLayer3, getLayerFE()).WillRepeatedly(Return(mLayer3FE));
- // getLayerFE() can return nullptr. Ensure that this is handled.
- EXPECT_CALL(*mLayer4, getLayerFE()).WillRepeatedly(Return(nullptr));
- }
-
sp<StrictMock<mock::LayerFE>> mLayer1FE{new StrictMock<mock::LayerFE>()};
sp<StrictMock<mock::LayerFE>> mLayer2FE{new StrictMock<mock::LayerFE>()};
sp<StrictMock<mock::LayerFE>> mLayer3FE{new StrictMock<mock::LayerFE>()};
@@ -256,7 +226,7 @@
EXPECT_CALL(*mLayer3FE, onPreComposition(_)).WillOnce(DoAll(SaveArg<0>(&ts3), Return(false)));
mRefreshArgs.outputs = {mOutput1};
- mRefreshArgs.layers = {mLayer1, mLayer2, mLayer3, mLayer4};
+ mRefreshArgs.layers = {mLayer1FE, mLayer2FE, mLayer3FE};
mEngine.preComposition(mRefreshArgs);
@@ -274,7 +244,7 @@
mEngine.setNeedsAnotherUpdateForTest(true);
mRefreshArgs.outputs = {mOutput1};
- mRefreshArgs.layers = {mLayer1, mLayer2, mLayer3, mLayer4};
+ mRefreshArgs.layers = {mLayer1FE, mLayer2FE, mLayer3FE};
mEngine.preComposition(mRefreshArgs);
@@ -289,7 +259,7 @@
EXPECT_CALL(*mLayer3FE, onPreComposition(_)).WillOnce(Return(false));
mRefreshArgs.outputs = {mOutput1};
- mRefreshArgs.layers = {mLayer1, mLayer2, mLayer3, mLayer4};
+ mRefreshArgs.layers = {mLayer1FE, mLayer2FE, mLayer3FE};
mEngine.preComposition(mRefreshArgs);
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index ae93969..16f7a4e 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -25,7 +25,6 @@
#include <compositionengine/mock/CompositionEngine.h>
#include <compositionengine/mock/DisplayColorProfile.h>
#include <compositionengine/mock/DisplaySurface.h>
-#include <compositionengine/mock/Layer.h>
#include <compositionengine/mock/LayerFE.h>
#include <compositionengine/mock/NativeWindow.h>
#include <compositionengine/mock/OutputLayer.h>
@@ -53,6 +52,27 @@
constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1920;
constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1080;
+struct Layer {
+ Layer() {
+ EXPECT_CALL(*outputLayer, getLayerFE()).WillRepeatedly(ReturnRef(*layerFE));
+ EXPECT_CALL(*outputLayer, getHwcLayer()).WillRepeatedly(Return(&hwc2Layer));
+ }
+
+ sp<mock::LayerFE> layerFE = new StrictMock<mock::LayerFE>();
+ StrictMock<mock::OutputLayer>* outputLayer = new StrictMock<mock::OutputLayer>();
+ StrictMock<HWC2::mock::Layer> hwc2Layer;
+};
+
+struct LayerNoHWC2Layer {
+ LayerNoHWC2Layer() {
+ EXPECT_CALL(*outputLayer, getLayerFE()).WillRepeatedly(ReturnRef(*layerFE));
+ EXPECT_CALL(*outputLayer, getHwcLayer()).WillRepeatedly(Return(nullptr));
+ }
+
+ sp<mock::LayerFE> layerFE = new StrictMock<mock::LayerFE>();
+ StrictMock<mock::OutputLayer>* outputLayer = new StrictMock<mock::OutputLayer>();
+};
+
struct DisplayTest : public testing::Test {
class Display : public impl::Display {
public:
@@ -71,28 +91,24 @@
DisplayTest() {
EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
- EXPECT_CALL(*mLayer1, getHwcLayer()).WillRepeatedly(Return(&mHWC2Layer1));
- EXPECT_CALL(*mLayer2, getHwcLayer()).WillRepeatedly(Return(&mHWC2Layer2));
- EXPECT_CALL(*mLayer3, getHwcLayer()).WillRepeatedly(Return(nullptr));
mDisplay->injectOutputLayerForTest(
- std::unique_ptr<compositionengine::OutputLayer>(mLayer1));
+ std::unique_ptr<compositionengine::OutputLayer>(mLayer1.outputLayer));
mDisplay->injectOutputLayerForTest(
- std::unique_ptr<compositionengine::OutputLayer>(mLayer2));
+ std::unique_ptr<compositionengine::OutputLayer>(mLayer2.outputLayer));
mDisplay->injectOutputLayerForTest(
- std::unique_ptr<compositionengine::OutputLayer>(mLayer3));
+ std::unique_ptr<compositionengine::OutputLayer>(mLayer3.outputLayer));
}
StrictMock<android::mock::HWComposer> mHwComposer;
StrictMock<Hwc2::mock::PowerAdvisor> mPowerAdvisor;
StrictMock<mock::CompositionEngine> mCompositionEngine;
sp<mock::NativeWindow> mNativeWindow = new StrictMock<mock::NativeWindow>();
- StrictMock<HWC2::mock::Layer> mHWC2Layer1;
- StrictMock<HWC2::mock::Layer> mHWC2Layer2;
- StrictMock<HWC2::mock::Layer> mHWC2LayerUnknown;
- mock::OutputLayer* mLayer1 = new StrictMock<mock::OutputLayer>();
- mock::OutputLayer* mLayer2 = new StrictMock<mock::OutputLayer>();
- mock::OutputLayer* mLayer3 = new StrictMock<mock::OutputLayer>();
+ Layer mLayer1;
+ Layer mLayer2;
+ LayerNoHWC2Layer mLayer3;
+ StrictMock<HWC2::mock::Layer> hwc2LayerUnknown;
+
std::shared_ptr<Display> mDisplay = createDisplay(mCompositionEngine,
DisplayCreationArgsBuilder()
.setDisplayId(DEFAULT_DISPLAY_ID)
@@ -283,12 +299,11 @@
TEST_F(DisplayTest, createOutputLayerSetsHwcLayer) {
sp<mock::LayerFE> layerFE = new StrictMock<mock::LayerFE>();
- auto layer = std::make_shared<StrictMock<mock::Layer>>();
StrictMock<HWC2::mock::Layer> hwcLayer;
EXPECT_CALL(mHwComposer, createLayer(DEFAULT_DISPLAY_ID)).WillOnce(Return(&hwcLayer));
- auto outputLayer = mDisplay->createOutputLayer(layer, layerFE);
+ auto outputLayer = mDisplay->createOutputLayer(layerFE);
EXPECT_EQ(&hwcLayer, outputLayer->getHwcLayer());
@@ -305,7 +320,6 @@
impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())};
sp<mock::LayerFE> layerXLayerFE = new StrictMock<mock::LayerFE>();
- mock::Layer layerXLayer;
{
Output::ReleasedLayers releasedLayers;
@@ -314,7 +328,7 @@
}
CompositionRefreshArgs refreshArgs;
- refreshArgs.layersWithQueuedFrames.push_back(&layerXLayer);
+ refreshArgs.layersWithQueuedFrames.push_back(layerXLayerFE);
nonHwcDisplay->setReleasedLayers(refreshArgs);
@@ -339,34 +353,19 @@
}
TEST_F(DisplayTest, setReleasedLayers) {
- sp<mock::LayerFE> layer1LayerFE = new StrictMock<mock::LayerFE>();
- sp<mock::LayerFE> layer2LayerFE = new StrictMock<mock::LayerFE>();
- sp<mock::LayerFE> layer3LayerFE = new StrictMock<mock::LayerFE>();
- sp<mock::LayerFE> layerXLayerFE = new StrictMock<mock::LayerFE>();
- mock::Layer layer1Layer;
- mock::Layer layer2Layer;
- mock::Layer layer3Layer;
- mock::Layer layerXLayer;
-
- EXPECT_CALL(*mLayer1, getLayer()).WillRepeatedly(ReturnRef(layer1Layer));
- EXPECT_CALL(*mLayer1, getLayerFE()).WillRepeatedly(ReturnRef(*layer1LayerFE.get()));
- EXPECT_CALL(*mLayer2, getLayer()).WillRepeatedly(ReturnRef(layer2Layer));
- EXPECT_CALL(*mLayer2, getLayerFE()).WillRepeatedly(ReturnRef(*layer2LayerFE.get()));
- EXPECT_CALL(*mLayer3, getLayer()).WillRepeatedly(ReturnRef(layer3Layer));
- EXPECT_CALL(*mLayer3, getLayerFE()).WillRepeatedly(ReturnRef(*layer3LayerFE.get()));
+ sp<mock::LayerFE> unknownLayer = new StrictMock<mock::LayerFE>();
CompositionRefreshArgs refreshArgs;
- refreshArgs.layersWithQueuedFrames.push_back(&layer1Layer);
- refreshArgs.layersWithQueuedFrames.push_back(&layer2Layer);
- refreshArgs.layersWithQueuedFrames.push_back(&layerXLayer);
- refreshArgs.layersWithQueuedFrames.push_back(nullptr);
+ refreshArgs.layersWithQueuedFrames.push_back(mLayer1.layerFE);
+ refreshArgs.layersWithQueuedFrames.push_back(mLayer2.layerFE);
+ refreshArgs.layersWithQueuedFrames.push_back(unknownLayer);
mDisplay->setReleasedLayers(refreshArgs);
const auto& releasedLayers = mDisplay->getReleasedLayersForTest();
ASSERT_EQ(2, releasedLayers.size());
- ASSERT_EQ(layer1LayerFE.get(), releasedLayers[0].promote().get());
- ASSERT_EQ(layer2LayerFE.get(), releasedLayers[1].promote().get());
+ ASSERT_EQ(mLayer1.layerFE.get(), releasedLayers[0].promote().get());
+ ASSERT_EQ(mLayer2.layerFE.get(), releasedLayers[1].promote().get());
}
/*
@@ -400,16 +399,12 @@
MOCK_CONST_METHOD0(getOutputLayerCount, size_t());
MOCK_CONST_METHOD1(getOutputLayerOrderedByZByIndex,
compositionengine::OutputLayer*(size_t));
- MOCK_METHOD3(ensureOutputLayer,
- compositionengine::OutputLayer*(
- std::optional<size_t>,
- const std::shared_ptr<compositionengine::Layer>&, const sp<LayerFE>&));
+ MOCK_METHOD2(ensureOutputLayer,
+ compositionengine::OutputLayer*(std::optional<size_t>, const sp<LayerFE>&));
MOCK_METHOD0(finalizePendingOutputLayers, void());
MOCK_METHOD0(clearOutputLayers, void());
MOCK_CONST_METHOD1(dumpState, void(std::string&));
- MOCK_METHOD2(injectOutputLayerForTest,
- compositionengine::OutputLayer*(
- const std::shared_ptr<compositionengine::Layer>&, const sp<LayerFE>&));
+ MOCK_METHOD1(injectOutputLayerForTest, compositionengine::OutputLayer*(const sp<LayerFE>&));
MOCK_METHOD1(injectOutputLayerForTest, void(std::unique_ptr<OutputLayer>));
const compositionengine::CompositionEngine& mCompositionEngine;
@@ -523,16 +518,16 @@
*/
TEST_F(DisplayTest, anyLayersRequireClientCompositionReturnsFalse) {
- EXPECT_CALL(*mLayer1, requiresClientComposition()).WillOnce(Return(false));
- EXPECT_CALL(*mLayer2, requiresClientComposition()).WillOnce(Return(false));
- EXPECT_CALL(*mLayer3, requiresClientComposition()).WillOnce(Return(false));
+ EXPECT_CALL(*mLayer1.outputLayer, requiresClientComposition()).WillOnce(Return(false));
+ EXPECT_CALL(*mLayer2.outputLayer, requiresClientComposition()).WillOnce(Return(false));
+ EXPECT_CALL(*mLayer3.outputLayer, requiresClientComposition()).WillOnce(Return(false));
EXPECT_FALSE(mDisplay->anyLayersRequireClientComposition());
}
TEST_F(DisplayTest, anyLayersRequireClientCompositionReturnsTrue) {
- EXPECT_CALL(*mLayer1, requiresClientComposition()).WillOnce(Return(false));
- EXPECT_CALL(*mLayer2, requiresClientComposition()).WillOnce(Return(true));
+ EXPECT_CALL(*mLayer1.outputLayer, requiresClientComposition()).WillOnce(Return(false));
+ EXPECT_CALL(*mLayer2.outputLayer, requiresClientComposition()).WillOnce(Return(true));
EXPECT_TRUE(mDisplay->anyLayersRequireClientComposition());
}
@@ -542,16 +537,16 @@
*/
TEST_F(DisplayTest, allLayersRequireClientCompositionReturnsTrue) {
- EXPECT_CALL(*mLayer1, requiresClientComposition()).WillOnce(Return(true));
- EXPECT_CALL(*mLayer2, requiresClientComposition()).WillOnce(Return(true));
- EXPECT_CALL(*mLayer3, requiresClientComposition()).WillOnce(Return(true));
+ EXPECT_CALL(*mLayer1.outputLayer, requiresClientComposition()).WillOnce(Return(true));
+ EXPECT_CALL(*mLayer2.outputLayer, requiresClientComposition()).WillOnce(Return(true));
+ EXPECT_CALL(*mLayer3.outputLayer, requiresClientComposition()).WillOnce(Return(true));
EXPECT_TRUE(mDisplay->allLayersRequireClientComposition());
}
TEST_F(DisplayTest, allLayersRequireClientCompositionReturnsFalse) {
- EXPECT_CALL(*mLayer1, requiresClientComposition()).WillOnce(Return(true));
- EXPECT_CALL(*mLayer2, requiresClientComposition()).WillOnce(Return(false));
+ EXPECT_CALL(*mLayer1.outputLayer, requiresClientComposition()).WillOnce(Return(true));
+ EXPECT_CALL(*mLayer2.outputLayer, requiresClientComposition()).WillOnce(Return(false));
EXPECT_FALSE(mDisplay->allLayersRequireClientComposition());
}
@@ -565,17 +560,17 @@
}
TEST_F(DisplayTest, applyChangedTypesToLayersAppliesChanges) {
- EXPECT_CALL(*mLayer1,
+ EXPECT_CALL(*mLayer1.outputLayer,
applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition::CLIENT))
.Times(1);
- EXPECT_CALL(*mLayer2,
+ EXPECT_CALL(*mLayer2.outputLayer,
applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition::DEVICE))
.Times(1);
mDisplay->applyChangedTypesToLayers(impl::Display::ChangedTypes{
- {&mHWC2Layer1, HWC2::Composition::Client},
- {&mHWC2Layer2, HWC2::Composition::Device},
- {&mHWC2LayerUnknown, HWC2::Composition::SolidColor},
+ {&mLayer1.hwc2Layer, HWC2::Composition::Client},
+ {&mLayer2.hwc2Layer, HWC2::Composition::Device},
+ {&hwc2LayerUnknown, HWC2::Composition::SolidColor},
});
}
@@ -616,25 +611,25 @@
*/
TEST_F(DisplayTest, applyLayerRequestsToLayersPreparesAllLayers) {
- EXPECT_CALL(*mLayer1, prepareForDeviceLayerRequests()).Times(1);
- EXPECT_CALL(*mLayer2, prepareForDeviceLayerRequests()).Times(1);
- EXPECT_CALL(*mLayer3, prepareForDeviceLayerRequests()).Times(1);
+ EXPECT_CALL(*mLayer1.outputLayer, prepareForDeviceLayerRequests()).Times(1);
+ EXPECT_CALL(*mLayer2.outputLayer, prepareForDeviceLayerRequests()).Times(1);
+ EXPECT_CALL(*mLayer3.outputLayer, prepareForDeviceLayerRequests()).Times(1);
mDisplay->applyLayerRequestsToLayers(impl::Display::LayerRequests());
}
TEST_F(DisplayTest, applyLayerRequestsToLayers2) {
- EXPECT_CALL(*mLayer1, prepareForDeviceLayerRequests()).Times(1);
- EXPECT_CALL(*mLayer2, prepareForDeviceLayerRequests()).Times(1);
- EXPECT_CALL(*mLayer3, prepareForDeviceLayerRequests()).Times(1);
+ EXPECT_CALL(*mLayer1.outputLayer, prepareForDeviceLayerRequests()).Times(1);
+ EXPECT_CALL(*mLayer2.outputLayer, prepareForDeviceLayerRequests()).Times(1);
+ EXPECT_CALL(*mLayer3.outputLayer, prepareForDeviceLayerRequests()).Times(1);
- EXPECT_CALL(*mLayer1,
+ EXPECT_CALL(*mLayer1.outputLayer,
applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest::CLEAR_CLIENT_TARGET))
.Times(1);
mDisplay->applyLayerRequestsToLayers(impl::Display::LayerRequests{
- {&mHWC2Layer1, HWC2::LayerRequest::ClearClientTarget},
- {&mHWC2LayerUnknown, HWC2::LayerRequest::ClearClientTarget},
+ {&mLayer1.hwc2Layer, HWC2::LayerRequest::ClearClientTarget},
+ {&hwc2LayerUnknown, HWC2::LayerRequest::ClearClientTarget},
});
}
@@ -660,9 +655,9 @@
EXPECT_CALL(mHwComposer, presentAndGetReleaseFences(DEFAULT_DISPLAY_ID)).Times(1);
EXPECT_CALL(mHwComposer, getPresentFence(DEFAULT_DISPLAY_ID)).WillOnce(Return(presentFence));
- EXPECT_CALL(mHwComposer, getLayerReleaseFence(DEFAULT_DISPLAY_ID, &mHWC2Layer1))
+ EXPECT_CALL(mHwComposer, getLayerReleaseFence(DEFAULT_DISPLAY_ID, &mLayer1.hwc2Layer))
.WillOnce(Return(layer1Fence));
- EXPECT_CALL(mHwComposer, getLayerReleaseFence(DEFAULT_DISPLAY_ID, &mHWC2Layer2))
+ EXPECT_CALL(mHwComposer, getLayerReleaseFence(DEFAULT_DISPLAY_ID, &mLayer2.hwc2Layer))
.WillOnce(Return(layer2Fence));
EXPECT_CALL(mHwComposer, clearReleaseFences(DEFAULT_DISPLAY_ID)).Times(1);
@@ -671,10 +666,10 @@
EXPECT_EQ(presentFence, result.presentFence);
EXPECT_EQ(2u, result.layerFences.size());
- ASSERT_EQ(1, result.layerFences.count(&mHWC2Layer1));
- EXPECT_EQ(layer1Fence, result.layerFences[&mHWC2Layer1]);
- ASSERT_EQ(1, result.layerFences.count(&mHWC2Layer2));
- EXPECT_EQ(layer2Fence, result.layerFences[&mHWC2Layer2]);
+ ASSERT_EQ(1, result.layerFences.count(&mLayer1.hwc2Layer));
+ EXPECT_EQ(layer1Fence, result.layerFences[&mLayer1.hwc2Layer]);
+ ASSERT_EQ(1, result.layerFences.count(&mLayer2.hwc2Layer));
+ EXPECT_EQ(layer2Fence, result.layerFences[&mLayer2.hwc2Layer]);
}
/*
diff --git a/services/surfaceflinger/CompositionEngine/tests/LayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/LayerTest.cpp
deleted file mode 100644
index 787f973..0000000
--- a/services/surfaceflinger/CompositionEngine/tests/LayerTest.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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 <gtest/gtest.h>
-
-#include <compositionengine/LayerCreationArgs.h>
-#include <compositionengine/LayerFECompositionState.h>
-#include <compositionengine/impl/Layer.h>
-#include <compositionengine/mock/CompositionEngine.h>
-#include <compositionengine/mock/LayerFE.h>
-
-namespace android::compositionengine {
-namespace {
-
-using testing::StrictMock;
-
-struct LayerTest : public testing::Test {
- struct Layer final : public impl::Layer {
- explicit Layer(const LayerCreationArgs& args) : mLayerFE(args.layerFE) {}
- ~Layer() override = default;
-
- // compositionengine::Layer overrides
- sp<LayerFE> getLayerFE() const { return mLayerFE.promote(); }
- const LayerFECompositionState& getFEState() const override { return mFrontEndState; }
- LayerFECompositionState& editFEState() override { return mFrontEndState; }
-
- // compositionengine::impl::Layer overrides
- void dumpFEState(std::string& out) const override { mFrontEndState.dump(out); }
-
- const wp<LayerFE> mLayerFE;
- LayerFECompositionState mFrontEndState;
- };
-
- ~LayerTest() override = default;
-
- StrictMock<mock::CompositionEngine> mCompositionEngine;
- sp<LayerFE> mLayerFE = new StrictMock<mock::LayerFE>();
- Layer mLayer{LayerCreationArgs{mLayerFE}};
-};
-
-/* ------------------------------------------------------------------------
- * Basic construction
- */
-
-TEST_F(LayerTest, canInstantiateLayer) {}
-
-} // namespace
-} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 0e579fa..963062f 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -18,7 +18,6 @@
#include <compositionengine/impl/OutputLayerCompositionState.h>
#include <compositionengine/mock/CompositionEngine.h>
#include <compositionengine/mock/DisplayColorProfile.h>
-#include <compositionengine/mock/Layer.h>
#include <compositionengine/mock/LayerFE.h>
#include <compositionengine/mock/Output.h>
#include <gtest/gtest.h>
@@ -56,15 +55,12 @@
struct OutputLayerTest : public testing::Test {
struct OutputLayer final : public impl::OutputLayer {
- OutputLayer(const compositionengine::Output& output,
- std::shared_ptr<compositionengine::Layer> layer,
- sp<compositionengine::LayerFE> layerFE)
- : mOutput(output), mLayer(layer), mLayerFE(layerFE) {}
+ OutputLayer(const compositionengine::Output& output, sp<compositionengine::LayerFE> layerFE)
+ : mOutput(output), mLayerFE(layerFE) {}
~OutputLayer() override = default;
// compositionengine::OutputLayer overrides
const compositionengine::Output& getOutput() const override { return mOutput; }
- compositionengine::Layer& getLayer() const override { return *mLayer; }
compositionengine::LayerFE& getLayerFE() const override { return *mLayerFE; }
const impl::OutputLayerCompositionState& getState() const override { return mState; }
impl::OutputLayerCompositionState& editState() override { return mState; }
@@ -73,7 +69,6 @@
void dumpState(std::string& out) const override { mState.dump(out); }
const compositionengine::Output& mOutput;
- std::shared_ptr<compositionengine::Layer> mLayer;
sp<compositionengine::LayerFE> mLayerFE;
impl::OutputLayerCompositionState mState;
};
@@ -82,16 +77,14 @@
EXPECT_CALL(*mLayerFE, getDebugName()).WillRepeatedly(Return("Test LayerFE"));
EXPECT_CALL(mOutput, getName()).WillRepeatedly(ReturnRef(kOutputName));
- EXPECT_CALL(*mLayer, getFEState()).WillRepeatedly(ReturnRef(mLayerFEState));
+ EXPECT_CALL(*mLayerFE, getCompositionState()).WillRepeatedly(Return(&mLayerFEState));
EXPECT_CALL(mOutput, getState()).WillRepeatedly(ReturnRef(mOutputState));
}
compositionengine::mock::Output mOutput;
- std::shared_ptr<compositionengine::mock::Layer> mLayer{
- new StrictMock<compositionengine::mock::Layer>()};
sp<compositionengine::mock::LayerFE> mLayerFE{
new StrictMock<compositionengine::mock::LayerFE>()};
- OutputLayer mOutputLayer{mOutput, mLayer, mLayerFE};
+ OutputLayer mOutputLayer{mOutput, mLayerFE};
LayerFECompositionState mLayerFEState;
impl::OutputCompositionState mOutputState;
@@ -436,9 +429,8 @@
struct OutputLayerPartialMockForUpdateCompositionState : public impl::OutputLayer {
OutputLayerPartialMockForUpdateCompositionState(const compositionengine::Output& output,
- std::shared_ptr<compositionengine::Layer> layer,
sp<compositionengine::LayerFE> layerFE)
- : mOutput(output), mLayer(layer), mLayerFE(layerFE) {}
+ : mOutput(output), mLayerFE(layerFE) {}
// Mock everything called by updateCompositionState to simplify testing it.
MOCK_CONST_METHOD0(calculateOutputSourceCrop, FloatRect());
MOCK_CONST_METHOD0(calculateOutputDisplayFrame, Rect());
@@ -446,7 +438,6 @@
// compositionengine::OutputLayer overrides
const compositionengine::Output& getOutput() const override { return mOutput; }
- compositionengine::Layer& getLayer() const override { return *mLayer; }
compositionengine::LayerFE& getLayerFE() const override { return *mLayerFE; }
const impl::OutputLayerCompositionState& getState() const override { return mState; }
impl::OutputLayerCompositionState& editState() override { return mState; }
@@ -455,7 +446,6 @@
MOCK_CONST_METHOD1(dumpState, void(std::string&));
const compositionengine::Output& mOutput;
- std::shared_ptr<compositionengine::Layer> mLayer;
sp<compositionengine::LayerFE> mLayerFE;
impl::OutputLayerCompositionState mState;
};
@@ -463,7 +453,6 @@
struct OutputLayerUpdateCompositionStateTest : public OutputLayerTest {
public:
OutputLayerUpdateCompositionStateTest() {
- EXPECT_CALL(*mLayer, getFEState()).WillRepeatedly(ReturnRef(mLayerFEState));
EXPECT_CALL(mOutput, getState()).WillRepeatedly(ReturnRef(mOutputState));
EXPECT_CALL(mOutput, getDisplayColorProfile())
.WillRepeatedly(Return(&mDisplayColorProfile));
@@ -491,10 +480,16 @@
uint32_t mBufferTransform{21};
using OutputLayer = OutputLayerPartialMockForUpdateCompositionState;
- StrictMock<OutputLayer> mOutputLayer{mOutput, mLayer, mLayerFE};
+ StrictMock<OutputLayer> mOutputLayer{mOutput, mLayerFE};
StrictMock<mock::DisplayColorProfile> mDisplayColorProfile;
};
+TEST_F(OutputLayerUpdateCompositionStateTest, doesNothingIfNoFECompositionState) {
+ EXPECT_CALL(*mLayerFE, getCompositionState()).WillOnce(Return(nullptr));
+
+ mOutputLayer.updateCompositionState(true, false);
+}
+
TEST_F(OutputLayerUpdateCompositionStateTest, setsStateNormally) {
mLayerFEState.isSecure = true;
mOutputState.isSecure = true;
@@ -745,6 +740,12 @@
const sp<GraphicBuffer> OutputLayerWriteStateToHWCTest::kBuffer;
const sp<Fence> OutputLayerWriteStateToHWCTest::kFence;
+TEST_F(OutputLayerWriteStateToHWCTest, doesNothingIfNoFECompositionState) {
+ EXPECT_CALL(*mLayerFE, getCompositionState()).WillOnce(Return(nullptr));
+
+ mOutputLayer.writeStateToHWC(true);
+}
+
TEST_F(OutputLayerWriteStateToHWCTest, doesNothingIfNoHWCState) {
mOutputLayer.editState().hwc.reset();
@@ -888,6 +889,12 @@
const Rect OutputLayerWriteCursorPositionToHWCTest::kDefaultDisplayViewport{0, 0, 1920, 1080};
const Rect OutputLayerWriteCursorPositionToHWCTest::kDefaultCursorFrame{1, 2, 3, 4};
+TEST_F(OutputLayerWriteCursorPositionToHWCTest, doesNothingIfNoFECompositionState) {
+ EXPECT_CALL(*mLayerFE, getCompositionState()).WillOnce(Return(nullptr));
+
+ mOutputLayer.writeCursorPositionToHWC();
+}
+
TEST_F(OutputLayerWriteCursorPositionToHWCTest, writeCursorPositionToHWCHandlesNoHwcState) {
mOutputLayer.editState().hwc.reset();
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 463d095..2b45046 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -23,7 +23,6 @@
#include <compositionengine/impl/OutputLayerCompositionState.h>
#include <compositionengine/mock/CompositionEngine.h>
#include <compositionengine/mock/DisplayColorProfile.h>
-#include <compositionengine/mock/Layer.h>
#include <compositionengine/mock/LayerFE.h>
#include <compositionengine/mock/OutputLayer.h>
#include <compositionengine/mock/RenderSurface.h>
@@ -78,22 +77,48 @@
// not implemented by the base implementation class.
MOCK_CONST_METHOD0(getOutputLayerCount, size_t());
MOCK_CONST_METHOD1(getOutputLayerOrderedByZByIndex, compositionengine::OutputLayer*(size_t));
- MOCK_METHOD3(ensureOutputLayer,
- compositionengine::OutputLayer*(std::optional<size_t>,
- const std::shared_ptr<compositionengine::Layer>&,
- const sp<LayerFE>&));
+ MOCK_METHOD2(ensureOutputLayer,
+ compositionengine::OutputLayer*(std::optional<size_t>, const sp<LayerFE>&));
MOCK_METHOD0(finalizePendingOutputLayers, void());
MOCK_METHOD0(clearOutputLayers, void());
MOCK_CONST_METHOD1(dumpState, void(std::string&));
MOCK_CONST_METHOD0(getCompositionEngine, const CompositionEngine&());
- MOCK_METHOD2(injectOutputLayerForTest,
- compositionengine::OutputLayer*(const std::shared_ptr<compositionengine::Layer>&,
- const sp<LayerFE>&));
+ MOCK_METHOD1(injectOutputLayerForTest, compositionengine::OutputLayer*(const sp<LayerFE>&));
MOCK_METHOD1(injectOutputLayerForTest, void(std::unique_ptr<OutputLayer>));
impl::OutputCompositionState mState;
};
+struct InjectedLayer {
+ InjectedLayer() {
+ EXPECT_CALL(*outputLayer, getLayerFE()).WillRepeatedly(ReturnRef(*layerFE.get()));
+ EXPECT_CALL(*outputLayer, getState()).WillRepeatedly(ReturnRef(outputLayerState));
+ EXPECT_CALL(*outputLayer, editState()).WillRepeatedly(ReturnRef(outputLayerState));
+
+ EXPECT_CALL(*layerFE, getCompositionState()).WillRepeatedly(Return(&layerFEState));
+ }
+
+ mock::OutputLayer* outputLayer = {new StrictMock<mock::OutputLayer>};
+ sp<StrictMock<mock::LayerFE>> layerFE = new StrictMock<mock::LayerFE>();
+ LayerFECompositionState layerFEState;
+ impl::OutputLayerCompositionState outputLayerState;
+};
+
+struct NonInjectedLayer {
+ NonInjectedLayer() {
+ EXPECT_CALL(outputLayer, getLayerFE()).WillRepeatedly(ReturnRef(*layerFE.get()));
+ EXPECT_CALL(outputLayer, getState()).WillRepeatedly(ReturnRef(outputLayerState));
+ EXPECT_CALL(outputLayer, editState()).WillRepeatedly(ReturnRef(outputLayerState));
+
+ EXPECT_CALL(*layerFE, getCompositionState()).WillRepeatedly(Return(&layerFEState));
+ }
+
+ mock::OutputLayer outputLayer;
+ sp<StrictMock<mock::LayerFE>> layerFE = new StrictMock<mock::LayerFE>();
+ LayerFECompositionState layerFEState;
+ impl::OutputLayerCompositionState outputLayerState;
+};
+
struct OutputTest : public testing::Test {
class Output : public impl::Output {
public:
@@ -114,6 +139,14 @@
mOutput->editState().bounds = kDefaultDisplaySize;
}
+ void injectOutputLayer(InjectedLayer& layer) {
+ mOutput->injectOutputLayerForTest(std::unique_ptr<OutputLayer>(layer.outputLayer));
+ }
+
+ void injectNullOutputLayer() {
+ mOutput->injectOutputLayerForTest(std::unique_ptr<OutputLayer>(nullptr));
+ }
+
static const Rect kDefaultDisplaySize;
StrictMock<mock::CompositionEngine> mCompositionEngine;
@@ -122,48 +155,6 @@
std::shared_ptr<Output> mOutput = createOutput(mCompositionEngine);
};
-// Extension of the base test useful for checking interactions with the LayerFE
-// functions to latch composition state.
-struct OutputLatchFEStateTest : public OutputTest {
- OutputLatchFEStateTest() {
- EXPECT_CALL(*mOutputLayer1, getLayer()).WillRepeatedly(ReturnRef(mLayer1));
- EXPECT_CALL(*mOutputLayer2, getLayer()).WillRepeatedly(ReturnRef(mLayer2));
- EXPECT_CALL(*mOutputLayer3, getLayer()).WillRepeatedly(ReturnRef(mLayer3));
-
- EXPECT_CALL(*mOutputLayer1, getLayerFE()).WillRepeatedly(ReturnRef(mLayer1FE));
- EXPECT_CALL(*mOutputLayer2, getLayerFE()).WillRepeatedly(ReturnRef(mLayer2FE));
- EXPECT_CALL(*mOutputLayer3, getLayerFE()).WillRepeatedly(ReturnRef(mLayer3FE));
-
- 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) {
- mOutput->injectOutputLayerForTest(std::unique_ptr<OutputLayer>(layer.release()));
- }
-
- std::unique_ptr<mock::OutputLayer> mOutputLayer1{new StrictMock<mock::OutputLayer>};
- std::unique_ptr<mock::OutputLayer> mOutputLayer2{new StrictMock<mock::OutputLayer>};
- std::unique_ptr<mock::OutputLayer> mOutputLayer3{new StrictMock<mock::OutputLayer>};
-
- StrictMock<mock::Layer> mLayer1;
- StrictMock<mock::Layer> mLayer2;
- StrictMock<mock::Layer> mLayer3;
-
- StrictMock<mock::LayerFE> mLayer1FE;
- StrictMock<mock::LayerFE> mLayer2FE;
- StrictMock<mock::LayerFE> mLayer3FE;
-
- LayerFECompositionState mLayer1FEState;
- LayerFECompositionState mLayer2FEState;
- LayerFECompositionState mLayer3FEState;
-};
-
const Rect OutputTest::kDefaultDisplaySize{100, 200};
using ColorProfile = compositionengine::Output::ColorProfile;
@@ -503,11 +494,18 @@
EXPECT_FALSE(mOutput->belongsInOutput(layerStack2, false));
}
-TEST_F(OutputTest, belongsInOutputFiltersLayersAsExpected) {
- StrictMock<mock::Layer> layer;
- LayerFECompositionState layerFEState;
+TEST_F(OutputTest, belongsInOutputHandlesLayerWithNoCompositionState) {
+ NonInjectedLayer layer;
+ sp<LayerFE> layerFE(layer.layerFE);
- EXPECT_CALL(layer, getFEState()).WillRepeatedly(ReturnRef(layerFEState));
+ // If the layer has no composition state, it does not belong to any output.
+ EXPECT_CALL(*layer.layerFE, getCompositionState).WillOnce(Return(nullptr));
+ EXPECT_FALSE(mOutput->belongsInOutput(layerFE));
+}
+
+TEST_F(OutputTest, belongsInOutputFiltersLayersAsExpected) {
+ NonInjectedLayer layer;
+ sp<LayerFE> layerFE(layer.layerFE);
const uint32_t layerStack1 = 123u;
const uint32_t layerStack2 = 456u;
@@ -515,57 +513,51 @@
// If the output accepts layerStack1 and internal-only layers....
mOutput->setLayerStackFilter(layerStack1, true);
- // A null layer pointer does not belong to the output
- EXPECT_FALSE(mOutput->belongsInOutput(nullptr));
-
// A layer with no layerStack does not belong to it, internal-only or not.
- layerFEState.layerStackId = std::nullopt;
- layerFEState.internalOnly = false;
- EXPECT_FALSE(mOutput->belongsInOutput(&layer));
+ layer.layerFEState.layerStackId = std::nullopt;
+ layer.layerFEState.internalOnly = false;
+ EXPECT_FALSE(mOutput->belongsInOutput(layerFE));
- layerFEState.layerStackId = std::nullopt;
- layerFEState.internalOnly = true;
- EXPECT_FALSE(mOutput->belongsInOutput(&layer));
+ layer.layerFEState.layerStackId = std::nullopt;
+ layer.layerFEState.internalOnly = true;
+ EXPECT_FALSE(mOutput->belongsInOutput(layerFE));
// Any layer with layerStack1 belongs to it, internal-only or not.
- layerFEState.layerStackId = layerStack1;
- layerFEState.internalOnly = false;
- EXPECT_TRUE(mOutput->belongsInOutput(&layer));
+ layer.layerFEState.layerStackId = layerStack1;
+ layer.layerFEState.internalOnly = false;
+ EXPECT_TRUE(mOutput->belongsInOutput(layerFE));
- layerFEState.layerStackId = layerStack1;
- layerFEState.internalOnly = true;
- EXPECT_TRUE(mOutput->belongsInOutput(&layer));
+ layer.layerFEState.layerStackId = layerStack1;
+ layer.layerFEState.internalOnly = true;
+ EXPECT_TRUE(mOutput->belongsInOutput(layerFE));
- layerFEState.layerStackId = layerStack2;
- layerFEState.internalOnly = true;
- EXPECT_FALSE(mOutput->belongsInOutput(&layer));
+ layer.layerFEState.layerStackId = layerStack2;
+ layer.layerFEState.internalOnly = true;
+ EXPECT_FALSE(mOutput->belongsInOutput(layerFE));
- layerFEState.layerStackId = layerStack2;
- layerFEState.internalOnly = false;
- EXPECT_FALSE(mOutput->belongsInOutput(&layer));
+ layer.layerFEState.layerStackId = layerStack2;
+ layer.layerFEState.internalOnly = false;
+ EXPECT_FALSE(mOutput->belongsInOutput(layerFE));
// If the output accepts layerStack1 but not internal-only layers...
mOutput->setLayerStackFilter(layerStack1, false);
- // A null layer pointer does not belong to the output
- EXPECT_FALSE(mOutput->belongsInOutput(nullptr));
-
// Only non-internal layers with layerStack1 belong to it.
- layerFEState.layerStackId = layerStack1;
- layerFEState.internalOnly = false;
- EXPECT_TRUE(mOutput->belongsInOutput(&layer));
+ layer.layerFEState.layerStackId = layerStack1;
+ layer.layerFEState.internalOnly = false;
+ EXPECT_TRUE(mOutput->belongsInOutput(layerFE));
- layerFEState.layerStackId = layerStack1;
- layerFEState.internalOnly = true;
- EXPECT_FALSE(mOutput->belongsInOutput(&layer));
+ layer.layerFEState.layerStackId = layerStack1;
+ layer.layerFEState.internalOnly = true;
+ EXPECT_FALSE(mOutput->belongsInOutput(layerFE));
- layerFEState.layerStackId = layerStack2;
- layerFEState.internalOnly = true;
- EXPECT_FALSE(mOutput->belongsInOutput(&layer));
+ layer.layerFEState.layerStackId = layerStack2;
+ layer.layerFEState.internalOnly = true;
+ EXPECT_FALSE(mOutput->belongsInOutput(layerFE));
- layerFEState.layerStackId = layerStack2;
- layerFEState.internalOnly = false;
- EXPECT_FALSE(mOutput->belongsInOutput(&layer));
+ layer.layerFEState.layerStackId = layerStack2;
+ layer.layerFEState.internalOnly = false;
+ EXPECT_FALSE(mOutput->belongsInOutput(layerFE));
}
/*
@@ -573,29 +565,27 @@
*/
TEST_F(OutputTest, getOutputLayerForLayerWorks) {
- mock::OutputLayer* outputLayer1 = new StrictMock<mock::OutputLayer>();
- mock::OutputLayer* outputLayer2 = new StrictMock<mock::OutputLayer>();
+ InjectedLayer layer1;
+ InjectedLayer layer2;
+ NonInjectedLayer layer3;
- mOutput->injectOutputLayerForTest(std::unique_ptr<OutputLayer>(outputLayer1));
- mOutput->injectOutputLayerForTest(nullptr);
- mOutput->injectOutputLayerForTest(std::unique_ptr<OutputLayer>(outputLayer2));
-
- StrictMock<mock::Layer> layer;
- StrictMock<mock::Layer> otherLayer;
+ injectOutputLayer(layer1);
+ injectNullOutputLayer();
+ injectOutputLayer(layer2);
// If the input layer matches the first OutputLayer, it will be returned.
- EXPECT_CALL(*outputLayer1, getLayer()).WillOnce(ReturnRef(layer));
- EXPECT_EQ(outputLayer1, mOutput->getOutputLayerForLayer(&layer));
+ EXPECT_CALL(*layer1.outputLayer, getLayerFE()).WillOnce(ReturnRef(*layer1.layerFE.get()));
+ EXPECT_EQ(layer1.outputLayer, mOutput->getOutputLayerForLayer(layer1.layerFE));
// If the input layer matches the second OutputLayer, it will be returned.
- EXPECT_CALL(*outputLayer1, getLayer()).WillOnce(ReturnRef(otherLayer));
- EXPECT_CALL(*outputLayer2, getLayer()).WillOnce(ReturnRef(layer));
- EXPECT_EQ(outputLayer2, mOutput->getOutputLayerForLayer(&layer));
+ EXPECT_CALL(*layer1.outputLayer, getLayerFE()).WillOnce(ReturnRef(*layer1.layerFE.get()));
+ EXPECT_CALL(*layer2.outputLayer, getLayerFE()).WillOnce(ReturnRef(*layer2.layerFE.get()));
+ EXPECT_EQ(layer2.outputLayer, mOutput->getOutputLayerForLayer(layer2.layerFE));
// If the input layer does not match an output layer, null will be returned.
- EXPECT_CALL(*outputLayer1, getLayer()).WillOnce(ReturnRef(otherLayer));
- EXPECT_CALL(*outputLayer2, getLayer()).WillOnce(ReturnRef(otherLayer));
- EXPECT_EQ(nullptr, mOutput->getOutputLayerForLayer(&layer));
+ EXPECT_CALL(*layer1.outputLayer, getLayerFE()).WillOnce(ReturnRef(*layer1.layerFE.get()));
+ EXPECT_CALL(*layer2.outputLayer, getLayerFE()).WillOnce(ReturnRef(*layer2.layerFE.get()));
+ EXPECT_EQ(nullptr, mOutput->getOutputLayerForLayer(layer3.layerFE));
}
/*
@@ -627,7 +617,7 @@
* Output::updateLayerStateFromFE()
*/
-using OutputUpdateLayerStateFromFETest = OutputLatchFEStateTest;
+using OutputUpdateLayerStateFromFETest = OutputTest;
TEST_F(OutputUpdateLayerStateFromFETest, handlesNoOutputLayerCase) {
CompositionRefreshArgs refreshArgs;
@@ -635,18 +625,18 @@
mOutput->updateLayerStateFromFE(refreshArgs);
}
-TEST_F(OutputUpdateLayerStateFromFETest, latchesContentStateForAllContainedLayers) {
- EXPECT_CALL(mLayer1FE,
- latchCompositionState(Ref(mLayer1FEState), LayerFE::StateSubset::Content));
- EXPECT_CALL(mLayer2FE,
- latchCompositionState(Ref(mLayer2FEState), LayerFE::StateSubset::Content));
- EXPECT_CALL(mLayer3FE,
- latchCompositionState(Ref(mLayer3FEState), LayerFE::StateSubset::Content));
+TEST_F(OutputUpdateLayerStateFromFETest, preparesContentStateForAllContainedLayers) {
+ InjectedLayer layer1;
+ InjectedLayer layer2;
+ InjectedLayer layer3;
- // Note: Must be performed after any expectations on these mocks
- injectLayer(std::move(mOutputLayer1));
- injectLayer(std::move(mOutputLayer2));
- injectLayer(std::move(mOutputLayer3));
+ EXPECT_CALL(*layer1.layerFE.get(), prepareCompositionState(LayerFE::StateSubset::Content));
+ EXPECT_CALL(*layer2.layerFE.get(), prepareCompositionState(LayerFE::StateSubset::Content));
+ EXPECT_CALL(*layer3.layerFE.get(), prepareCompositionState(LayerFE::StateSubset::Content));
+
+ injectOutputLayer(layer1);
+ injectOutputLayer(layer2);
+ injectOutputLayer(layer3);
CompositionRefreshArgs refreshArgs;
refreshArgs.updatingGeometryThisFrame = false;
@@ -654,21 +644,18 @@
mOutput->updateLayerStateFromFE(refreshArgs);
}
-TEST_F(OutputUpdateLayerStateFromFETest, latchesGeometryAndContentStateForAllContainedLayers) {
- EXPECT_CALL(mLayer1FE,
- latchCompositionState(Ref(mLayer1FEState),
- LayerFE::StateSubset::GeometryAndContent));
- EXPECT_CALL(mLayer2FE,
- latchCompositionState(Ref(mLayer2FEState),
- LayerFE::StateSubset::GeometryAndContent));
- EXPECT_CALL(mLayer3FE,
- latchCompositionState(Ref(mLayer3FEState),
- LayerFE::StateSubset::GeometryAndContent));
+TEST_F(OutputUpdateLayerStateFromFETest, preparesGeometryAndContentStateForAllContainedLayers) {
+ InjectedLayer layer1;
+ InjectedLayer layer2;
+ InjectedLayer layer3;
- // Note: Must be performed after any expectations on these mocks
- injectLayer(std::move(mOutputLayer1));
- injectLayer(std::move(mOutputLayer2));
- injectLayer(std::move(mOutputLayer3));
+ EXPECT_CALL(*layer1.layerFE, prepareCompositionState(LayerFE::StateSubset::GeometryAndContent));
+ EXPECT_CALL(*layer2.layerFE, prepareCompositionState(LayerFE::StateSubset::GeometryAndContent));
+ EXPECT_CALL(*layer3.layerFE, prepareCompositionState(LayerFE::StateSubset::GeometryAndContent));
+
+ injectOutputLayer(layer1);
+ injectOutputLayer(layer2);
+ injectOutputLayer(layer3);
CompositionRefreshArgs refreshArgs;
refreshArgs.updatingGeometryThisFrame = true;
@@ -680,7 +667,7 @@
* Output::updateAndWriteCompositionState()
*/
-using OutputUpdateAndWriteCompositionStateTest = OutputLatchFEStateTest;
+using OutputUpdateAndWriteCompositionStateTest = OutputTest;
TEST_F(OutputUpdateAndWriteCompositionStateTest, doesNothingIfLayers) {
mOutput->editState().isEnabled = true;
@@ -690,27 +677,35 @@
}
TEST_F(OutputUpdateAndWriteCompositionStateTest, doesNothingIfOutputNotEnabled) {
+ InjectedLayer layer1;
+ InjectedLayer layer2;
+ InjectedLayer layer3;
+
mOutput->editState().isEnabled = false;
- injectLayer(std::move(mOutputLayer1));
- injectLayer(std::move(mOutputLayer2));
- injectLayer(std::move(mOutputLayer3));
+ injectOutputLayer(layer1);
+ injectOutputLayer(layer2);
+ injectOutputLayer(layer3);
CompositionRefreshArgs args;
mOutput->updateAndWriteCompositionState(args);
}
TEST_F(OutputUpdateAndWriteCompositionStateTest, updatesLayerContentForAllLayers) {
- EXPECT_CALL(*mOutputLayer1, updateCompositionState(false, false));
- EXPECT_CALL(*mOutputLayer1, writeStateToHWC(false));
- EXPECT_CALL(*mOutputLayer2, updateCompositionState(false, false));
- EXPECT_CALL(*mOutputLayer2, writeStateToHWC(false));
- EXPECT_CALL(*mOutputLayer3, updateCompositionState(false, false));
- EXPECT_CALL(*mOutputLayer3, writeStateToHWC(false));
+ InjectedLayer layer1;
+ InjectedLayer layer2;
+ InjectedLayer layer3;
- injectLayer(std::move(mOutputLayer1));
- injectLayer(std::move(mOutputLayer2));
- injectLayer(std::move(mOutputLayer3));
+ EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, false));
+ EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(false));
+ EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, false));
+ EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(false));
+ EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false));
+ EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(false));
+
+ injectOutputLayer(layer1);
+ injectOutputLayer(layer2);
+ injectOutputLayer(layer3);
mOutput->editState().isEnabled = true;
@@ -721,16 +716,20 @@
}
TEST_F(OutputUpdateAndWriteCompositionStateTest, updatesLayerGeometryAndContentForAllLayers) {
- EXPECT_CALL(*mOutputLayer1, updateCompositionState(true, false));
- EXPECT_CALL(*mOutputLayer1, writeStateToHWC(true));
- EXPECT_CALL(*mOutputLayer2, updateCompositionState(true, false));
- EXPECT_CALL(*mOutputLayer2, writeStateToHWC(true));
- EXPECT_CALL(*mOutputLayer3, updateCompositionState(true, false));
- EXPECT_CALL(*mOutputLayer3, writeStateToHWC(true));
+ InjectedLayer layer1;
+ InjectedLayer layer2;
+ InjectedLayer layer3;
- injectLayer(std::move(mOutputLayer1));
- injectLayer(std::move(mOutputLayer2));
- injectLayer(std::move(mOutputLayer3));
+ EXPECT_CALL(*layer1.outputLayer, updateCompositionState(true, false));
+ EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(true));
+ EXPECT_CALL(*layer2.outputLayer, updateCompositionState(true, false));
+ EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(true));
+ EXPECT_CALL(*layer3.outputLayer, updateCompositionState(true, false));
+ EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(true));
+
+ injectOutputLayer(layer1);
+ injectOutputLayer(layer2);
+ injectOutputLayer(layer3);
mOutput->editState().isEnabled = true;
@@ -741,16 +740,20 @@
}
TEST_F(OutputUpdateAndWriteCompositionStateTest, forcesClientCompositionForAllLayers) {
- 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, true));
- EXPECT_CALL(*mOutputLayer3, writeStateToHWC(false));
+ InjectedLayer layer1;
+ InjectedLayer layer2;
+ InjectedLayer layer3;
- injectLayer(std::move(mOutputLayer1));
- injectLayer(std::move(mOutputLayer2));
- injectLayer(std::move(mOutputLayer3));
+ EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true));
+ EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(false));
+ EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true));
+ EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(false));
+ EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, true));
+ EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(false));
+
+ injectOutputLayer(layer1);
+ injectOutputLayer(layer2);
+ injectOutputLayer(layer3);
mOutput->editState().isEnabled = true;
@@ -972,7 +975,7 @@
// Sets up the helper functions called by the function under test to use
// mock implementations.
MOCK_METHOD2(ensureOutputLayerIfVisible,
- void(std::shared_ptr<compositionengine::Layer>,
+ void(sp<compositionengine::LayerFE>&,
compositionengine::Output::CoverageState&));
MOCK_METHOD1(setReleasedLayers, void(const compositionengine::CompositionRefreshArgs&));
MOCK_METHOD0(finalizePendingOutputLayers, void());
@@ -985,8 +988,8 @@
}
StrictMock<mock::OutputLayer> outputLayer;
- std::shared_ptr<StrictMock<mock::Layer>> layer{new StrictMock<mock::Layer>()};
impl::OutputLayerCompositionState outputLayerState;
+ sp<StrictMock<mock::LayerFE>> layerFE{new StrictMock<mock::LayerFE>()};
};
OutputCollectVisibleLayersTest() {
@@ -998,9 +1001,9 @@
EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(2))
.WillRepeatedly(Return(&mLayer3.outputLayer));
- mRefreshArgs.layers.push_back(mLayer1.layer);
- mRefreshArgs.layers.push_back(mLayer2.layer);
- mRefreshArgs.layers.push_back(mLayer3.layer);
+ mRefreshArgs.layers.push_back(mLayer1.layerFE);
+ mRefreshArgs.layers.push_back(mLayer2.layerFE);
+ mRefreshArgs.layers.push_back(mLayer3.layerFE);
}
StrictMock<OutputPartialMock> mOutput;
@@ -1027,9 +1030,9 @@
InSequence seq;
// Layer coverage is evaluated from front to back!
- EXPECT_CALL(mOutput, ensureOutputLayerIfVisible(Eq(mLayer3.layer), Ref(mCoverageState)));
- EXPECT_CALL(mOutput, ensureOutputLayerIfVisible(Eq(mLayer2.layer), Ref(mCoverageState)));
- EXPECT_CALL(mOutput, ensureOutputLayerIfVisible(Eq(mLayer1.layer), Ref(mCoverageState)));
+ EXPECT_CALL(mOutput, ensureOutputLayerIfVisible(Eq(mLayer3.layerFE), Ref(mCoverageState)));
+ EXPECT_CALL(mOutput, ensureOutputLayerIfVisible(Eq(mLayer2.layerFE), Ref(mCoverageState)));
+ EXPECT_CALL(mOutput, ensureOutputLayerIfVisible(Eq(mLayer1.layerFE), Ref(mCoverageState)));
EXPECT_CALL(mOutput, setReleasedLayers(Ref(mRefreshArgs)));
EXPECT_CALL(mOutput, finalizePendingOutputLayers());
@@ -1050,43 +1053,39 @@
struct OutputPartialMock : public OutputPartialMockBase {
// Sets up the helper functions called by the function under test to use
// mock implementations.
- MOCK_CONST_METHOD1(belongsInOutput, bool(const compositionengine::Layer*));
+ MOCK_CONST_METHOD1(belongsInOutput, bool(const sp<compositionengine::LayerFE>&));
MOCK_CONST_METHOD1(getOutputLayerOrderedByZByIndex, OutputLayer*(size_t));
- MOCK_METHOD3(ensureOutputLayer,
- compositionengine::OutputLayer*(
- std::optional<size_t>,
- const std::shared_ptr<compositionengine::Layer>&, const sp<LayerFE>&));
+ MOCK_METHOD2(ensureOutputLayer,
+ compositionengine::OutputLayer*(std::optional<size_t>, const sp<LayerFE>&));
};
OutputEnsureOutputLayerIfVisibleTest() {
- EXPECT_CALL(*mLayer, getLayerFE()).WillRepeatedly(Return(mLayerFE));
- EXPECT_CALL(*mLayer, getFEState()).WillRepeatedly(ReturnRef(mLayerFEState));
- EXPECT_CALL(*mLayer, editFEState()).WillRepeatedly(ReturnRef(mLayerFEState));
-
- EXPECT_CALL(mOutput, belongsInOutput(mLayer.get())).WillRepeatedly(Return(true));
+ EXPECT_CALL(mOutput, belongsInOutput(sp<LayerFE>(mLayer.layerFE)))
+ .WillRepeatedly(Return(true));
EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(1u));
EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(0u))
- .WillRepeatedly(Return(&mOutputLayer));
-
- EXPECT_CALL(mOutputLayer, getState()).WillRepeatedly(ReturnRef(mOutputLayerState));
- EXPECT_CALL(mOutputLayer, editState()).WillRepeatedly(ReturnRef(mOutputLayerState));
- EXPECT_CALL(mOutputLayer, getLayer()).WillRepeatedly(ReturnRef(*mLayer.get()));
+ .WillRepeatedly(Return(&mLayer.outputLayer));
mOutput.mState.bounds = Rect(0, 0, 200, 300);
mOutput.mState.viewport = Rect(0, 0, 200, 300);
mOutput.mState.transform = ui::Transform(TR_IDENT, 200, 300);
- mLayerFEState.isVisible = true;
- mLayerFEState.isOpaque = true;
- mLayerFEState.contentDirty = true;
- mLayerFEState.geomLayerBounds = FloatRect{0, 0, 100, 200};
- mLayerFEState.geomLayerTransform = ui::Transform(TR_IDENT, 100, 200);
- mLayerFEState.transparentRegionHint = Region(Rect(0, 0, 100, 100));
+ mLayer.layerFEState.isVisible = true;
+ mLayer.layerFEState.isOpaque = true;
+ mLayer.layerFEState.contentDirty = true;
+ mLayer.layerFEState.geomLayerBounds = FloatRect{0, 0, 100, 200};
+ mLayer.layerFEState.geomLayerTransform = ui::Transform(TR_IDENT, 100, 200);
+ mLayer.layerFEState.transparentRegionHint = Region(Rect(0, 0, 100, 100));
- mOutputLayerState.visibleRegion = Region(Rect(0, 0, 50, 200));
- mOutputLayerState.coveredRegion = Region(Rect(50, 0, 100, 200));
+ mLayer.outputLayerState.visibleRegion = Region(Rect(0, 0, 50, 200));
+ mLayer.outputLayerState.coveredRegion = Region(Rect(50, 0, 100, 200));
- mGeomSnapshots.insert(mLayerFE);
+ mGeomSnapshots.insert(mLayer.layerFE);
+ }
+
+ void ensureOutputLayerIfVisible() {
+ sp<LayerFE> layerFE(mLayer.layerFE);
+ mOutput.ensureOutputLayerIfVisible(layerFE, mCoverageState);
}
static const Region kEmptyRegion;
@@ -1099,11 +1098,7 @@
LayerFESet mGeomSnapshots;
Output::CoverageState mCoverageState{mGeomSnapshots};
- std::shared_ptr<mock::Layer> mLayer{new StrictMock<mock::Layer>()};
- sp<StrictMock<mock::LayerFE>> mLayerFE{new StrictMock<mock::LayerFE>()};
- LayerFECompositionState mLayerFEState;
- mock::OutputLayer mOutputLayer;
- impl::OutputLayerCompositionState mOutputLayerState;
+ NonInjectedLayer mLayer;
};
const Region OutputEnsureOutputLayerIfVisibleTest::kEmptyRegion = Region(Rect(0, 0, 0, 0));
@@ -1116,275 +1111,282 @@
const Region OutputEnsureOutputLayerIfVisibleTest::kFullBounds90Rotation =
Region(Rect(0, 0, 200, 100));
-TEST_F(OutputEnsureOutputLayerIfVisibleTest, doesNothingIfNoLayerFE) {
- EXPECT_CALL(*mLayer, getLayerFE).WillOnce(Return(sp<LayerFE>()));
-
- mOutput.ensureOutputLayerIfVisible(mLayer, mCoverageState);
-}
-
TEST_F(OutputEnsureOutputLayerIfVisibleTest, performsGeomLatchBeforeCheckingIfLayerBelongs) {
- EXPECT_CALL(mOutput, belongsInOutput(mLayer.get())).WillOnce(Return(false));
- EXPECT_CALL(*mLayerFE.get(),
- latchCompositionState(Ref(mLayerFEState),
- compositionengine::LayerFE::StateSubset::BasicGeometry));
+ EXPECT_CALL(mOutput, belongsInOutput(sp<LayerFE>(mLayer.layerFE))).WillOnce(Return(false));
+ EXPECT_CALL(*mLayer.layerFE,
+ prepareCompositionState(compositionengine::LayerFE::StateSubset::BasicGeometry));
mGeomSnapshots.clear();
- mOutput.ensureOutputLayerIfVisible(mLayer, mCoverageState);
+ ensureOutputLayerIfVisible();
}
TEST_F(OutputEnsureOutputLayerIfVisibleTest,
skipsLatchIfAlreadyLatchedBeforeCheckingIfLayerBelongs) {
- EXPECT_CALL(mOutput, belongsInOutput(mLayer.get())).WillOnce(Return(false));
+ EXPECT_CALL(mOutput, belongsInOutput(sp<LayerFE>(mLayer.layerFE))).WillOnce(Return(false));
- mOutput.ensureOutputLayerIfVisible(mLayer, mCoverageState);
+ ensureOutputLayerIfVisible();
+}
+
+TEST_F(OutputEnsureOutputLayerIfVisibleTest, takesEarlyOutIfLayerHasNoCompositionState) {
+ EXPECT_CALL(*mLayer.layerFE, getCompositionState()).WillOnce(Return(nullptr));
+
+ ensureOutputLayerIfVisible();
}
TEST_F(OutputEnsureOutputLayerIfVisibleTest, takesEarlyOutIfLayerNotVisible) {
- mLayerFEState.isVisible = false;
+ mLayer.layerFEState.isVisible = false;
- mOutput.ensureOutputLayerIfVisible(mLayer, mCoverageState);
+ ensureOutputLayerIfVisible();
}
TEST_F(OutputEnsureOutputLayerIfVisibleTest, takesEarlyOutIfLayerHasEmptyVisibleRegion) {
- mLayerFEState.geomLayerBounds = FloatRect{0, 0, 0, 0};
+ mLayer.layerFEState.geomLayerBounds = FloatRect{0, 0, 0, 0};
- mOutput.ensureOutputLayerIfVisible(mLayer, mCoverageState);
+ ensureOutputLayerIfVisible();
}
TEST_F(OutputEnsureOutputLayerIfVisibleTest, takesNotSoEarlyOutifDrawRegionEmpty) {
mOutput.mState.bounds = Rect(0, 0, 0, 0);
- mOutput.ensureOutputLayerIfVisible(mLayer, mCoverageState);
+ ensureOutputLayerIfVisible();
}
TEST_F(OutputEnsureOutputLayerIfVisibleTest,
handlesCreatingOutputLayerForOpaqueDirtyNotRotatedLayer) {
- mLayerFEState.isOpaque = true;
- mLayerFEState.contentDirty = true;
- mLayerFEState.geomLayerTransform = ui::Transform(TR_IDENT, 100, 200);
+ mLayer.layerFEState.isOpaque = true;
+ mLayer.layerFEState.contentDirty = true;
+ mLayer.layerFEState.geomLayerTransform = ui::Transform(TR_IDENT, 100, 200);
EXPECT_CALL(mOutput, getOutputLayerCount()).WillOnce(Return(0u));
- EXPECT_CALL(mOutput, ensureOutputLayer(Eq(std::nullopt), Eq(mLayer), Eq(mLayerFE)))
- .WillOnce(Return(&mOutputLayer));
+ EXPECT_CALL(mOutput, ensureOutputLayer(Eq(std::nullopt), Eq(mLayer.layerFE)))
+ .WillOnce(Return(&mLayer.outputLayer));
- mOutput.ensureOutputLayerIfVisible(mLayer, mCoverageState);
+ ensureOutputLayerIfVisible();
EXPECT_THAT(mCoverageState.dirtyRegion, RegionEq(kFullBoundsNoRotation));
EXPECT_THAT(mCoverageState.aboveCoveredLayers, RegionEq(kFullBoundsNoRotation));
EXPECT_THAT(mCoverageState.aboveOpaqueLayers, RegionEq(kFullBoundsNoRotation));
- EXPECT_THAT(mOutputLayerState.visibleRegion, RegionEq(kFullBoundsNoRotation));
- EXPECT_THAT(mOutputLayerState.visibleNonTransparentRegion, RegionEq(kFullBoundsNoRotation));
- EXPECT_THAT(mOutputLayerState.coveredRegion, RegionEq(kEmptyRegion));
- EXPECT_THAT(mOutputLayerState.outputSpaceVisibleRegion, RegionEq(kFullBoundsNoRotation));
+ EXPECT_THAT(mLayer.outputLayerState.visibleRegion, RegionEq(kFullBoundsNoRotation));
+ EXPECT_THAT(mLayer.outputLayerState.visibleNonTransparentRegion,
+ RegionEq(kFullBoundsNoRotation));
+ EXPECT_THAT(mLayer.outputLayerState.coveredRegion, RegionEq(kEmptyRegion));
+ EXPECT_THAT(mLayer.outputLayerState.outputSpaceVisibleRegion, RegionEq(kFullBoundsNoRotation));
}
TEST_F(OutputEnsureOutputLayerIfVisibleTest,
handlesUpdatingOutputLayerForOpaqueDirtyNotRotatedLayer) {
- mLayerFEState.isOpaque = true;
- mLayerFEState.contentDirty = true;
- mLayerFEState.geomLayerTransform = ui::Transform(TR_IDENT, 100, 200);
+ mLayer.layerFEState.isOpaque = true;
+ mLayer.layerFEState.contentDirty = true;
+ mLayer.layerFEState.geomLayerTransform = ui::Transform(TR_IDENT, 100, 200);
- EXPECT_CALL(mOutput, ensureOutputLayer(Eq(0u), Eq(mLayer), Eq(mLayerFE)))
- .WillOnce(Return(&mOutputLayer));
+ EXPECT_CALL(mOutput, ensureOutputLayer(Eq(0u), Eq(mLayer.layerFE)))
+ .WillOnce(Return(&mLayer.outputLayer));
- mOutput.ensureOutputLayerIfVisible(mLayer, mCoverageState);
+ ensureOutputLayerIfVisible();
EXPECT_THAT(mCoverageState.dirtyRegion, RegionEq(kFullBoundsNoRotation));
EXPECT_THAT(mCoverageState.aboveCoveredLayers, RegionEq(kFullBoundsNoRotation));
EXPECT_THAT(mCoverageState.aboveOpaqueLayers, RegionEq(kFullBoundsNoRotation));
- EXPECT_THAT(mOutputLayerState.visibleRegion, RegionEq(kFullBoundsNoRotation));
- EXPECT_THAT(mOutputLayerState.visibleNonTransparentRegion, RegionEq(kFullBoundsNoRotation));
- EXPECT_THAT(mOutputLayerState.coveredRegion, RegionEq(kEmptyRegion));
- EXPECT_THAT(mOutputLayerState.outputSpaceVisibleRegion, RegionEq(kFullBoundsNoRotation));
+ EXPECT_THAT(mLayer.outputLayerState.visibleRegion, RegionEq(kFullBoundsNoRotation));
+ EXPECT_THAT(mLayer.outputLayerState.visibleNonTransparentRegion,
+ RegionEq(kFullBoundsNoRotation));
+ EXPECT_THAT(mLayer.outputLayerState.coveredRegion, RegionEq(kEmptyRegion));
+ EXPECT_THAT(mLayer.outputLayerState.outputSpaceVisibleRegion, RegionEq(kFullBoundsNoRotation));
}
TEST_F(OutputEnsureOutputLayerIfVisibleTest,
handlesCreatingOutputLayerForTransparentDirtyNotRotatedLayer) {
- mLayerFEState.isOpaque = false;
- mLayerFEState.contentDirty = true;
- mLayerFEState.geomLayerTransform = ui::Transform(TR_IDENT, 100, 200);
+ mLayer.layerFEState.isOpaque = false;
+ mLayer.layerFEState.contentDirty = true;
+ mLayer.layerFEState.geomLayerTransform = ui::Transform(TR_IDENT, 100, 200);
EXPECT_CALL(mOutput, getOutputLayerCount()).WillOnce(Return(0u));
- EXPECT_CALL(mOutput, ensureOutputLayer(Eq(std::nullopt), Eq(mLayer), Eq(mLayerFE)))
- .WillOnce(Return(&mOutputLayer));
+ EXPECT_CALL(mOutput, ensureOutputLayer(Eq(std::nullopt), Eq(mLayer.layerFE)))
+ .WillOnce(Return(&mLayer.outputLayer));
- mOutput.ensureOutputLayerIfVisible(mLayer, mCoverageState);
+ ensureOutputLayerIfVisible();
EXPECT_THAT(mCoverageState.dirtyRegion, RegionEq(kFullBoundsNoRotation));
EXPECT_THAT(mCoverageState.aboveCoveredLayers, RegionEq(kFullBoundsNoRotation));
EXPECT_THAT(mCoverageState.aboveOpaqueLayers, RegionEq(kEmptyRegion));
- EXPECT_THAT(mOutputLayerState.visibleRegion, RegionEq(kFullBoundsNoRotation));
- EXPECT_THAT(mOutputLayerState.visibleNonTransparentRegion,
+ EXPECT_THAT(mLayer.outputLayerState.visibleRegion, RegionEq(kFullBoundsNoRotation));
+ EXPECT_THAT(mLayer.outputLayerState.visibleNonTransparentRegion,
RegionEq(kRightHalfBoundsNoRotation));
- EXPECT_THAT(mOutputLayerState.coveredRegion, RegionEq(kEmptyRegion));
- EXPECT_THAT(mOutputLayerState.outputSpaceVisibleRegion, RegionEq(kFullBoundsNoRotation));
+ EXPECT_THAT(mLayer.outputLayerState.coveredRegion, RegionEq(kEmptyRegion));
+ EXPECT_THAT(mLayer.outputLayerState.outputSpaceVisibleRegion, RegionEq(kFullBoundsNoRotation));
}
TEST_F(OutputEnsureOutputLayerIfVisibleTest,
handlesUpdatingOutputLayerForTransparentDirtyNotRotatedLayer) {
- mLayerFEState.isOpaque = false;
- mLayerFEState.contentDirty = true;
- mLayerFEState.geomLayerTransform = ui::Transform(TR_IDENT, 100, 200);
+ mLayer.layerFEState.isOpaque = false;
+ mLayer.layerFEState.contentDirty = true;
+ mLayer.layerFEState.geomLayerTransform = ui::Transform(TR_IDENT, 100, 200);
- EXPECT_CALL(mOutput, ensureOutputLayer(Eq(0u), Eq(mLayer), Eq(mLayerFE)))
- .WillOnce(Return(&mOutputLayer));
+ EXPECT_CALL(mOutput, ensureOutputLayer(Eq(0u), Eq(mLayer.layerFE)))
+ .WillOnce(Return(&mLayer.outputLayer));
- mOutput.ensureOutputLayerIfVisible(mLayer, mCoverageState);
+ ensureOutputLayerIfVisible();
EXPECT_THAT(mCoverageState.dirtyRegion, RegionEq(kFullBoundsNoRotation));
EXPECT_THAT(mCoverageState.aboveCoveredLayers, RegionEq(kFullBoundsNoRotation));
EXPECT_THAT(mCoverageState.aboveOpaqueLayers, RegionEq(kEmptyRegion));
- EXPECT_THAT(mOutputLayerState.visibleRegion, RegionEq(kFullBoundsNoRotation));
- EXPECT_THAT(mOutputLayerState.visibleNonTransparentRegion,
+ EXPECT_THAT(mLayer.outputLayerState.visibleRegion, RegionEq(kFullBoundsNoRotation));
+ EXPECT_THAT(mLayer.outputLayerState.visibleNonTransparentRegion,
RegionEq(kRightHalfBoundsNoRotation));
- EXPECT_THAT(mOutputLayerState.coveredRegion, RegionEq(kEmptyRegion));
- EXPECT_THAT(mOutputLayerState.outputSpaceVisibleRegion, RegionEq(kFullBoundsNoRotation));
+ EXPECT_THAT(mLayer.outputLayerState.coveredRegion, RegionEq(kEmptyRegion));
+ EXPECT_THAT(mLayer.outputLayerState.outputSpaceVisibleRegion, RegionEq(kFullBoundsNoRotation));
}
TEST_F(OutputEnsureOutputLayerIfVisibleTest,
handlesCreatingOutputLayerForOpaqueNonDirtyNotRotatedLayer) {
- mLayerFEState.isOpaque = true;
- mLayerFEState.contentDirty = false;
- mLayerFEState.geomLayerTransform = ui::Transform(TR_IDENT, 100, 200);
+ mLayer.layerFEState.isOpaque = true;
+ mLayer.layerFEState.contentDirty = false;
+ mLayer.layerFEState.geomLayerTransform = ui::Transform(TR_IDENT, 100, 200);
EXPECT_CALL(mOutput, getOutputLayerCount()).WillOnce(Return(0u));
- EXPECT_CALL(mOutput, ensureOutputLayer(Eq(std::nullopt), Eq(mLayer), Eq(mLayerFE)))
- .WillOnce(Return(&mOutputLayer));
+ EXPECT_CALL(mOutput, ensureOutputLayer(Eq(std::nullopt), Eq(mLayer.layerFE)))
+ .WillOnce(Return(&mLayer.outputLayer));
- mOutput.ensureOutputLayerIfVisible(mLayer, mCoverageState);
+ ensureOutputLayerIfVisible();
EXPECT_THAT(mCoverageState.dirtyRegion, RegionEq(kFullBoundsNoRotation));
EXPECT_THAT(mCoverageState.aboveCoveredLayers, RegionEq(kFullBoundsNoRotation));
EXPECT_THAT(mCoverageState.aboveOpaqueLayers, RegionEq(kFullBoundsNoRotation));
- EXPECT_THAT(mOutputLayerState.visibleRegion, RegionEq(kFullBoundsNoRotation));
- EXPECT_THAT(mOutputLayerState.visibleNonTransparentRegion, RegionEq(kFullBoundsNoRotation));
- EXPECT_THAT(mOutputLayerState.coveredRegion, RegionEq(kEmptyRegion));
- EXPECT_THAT(mOutputLayerState.outputSpaceVisibleRegion, RegionEq(kFullBoundsNoRotation));
+ EXPECT_THAT(mLayer.outputLayerState.visibleRegion, RegionEq(kFullBoundsNoRotation));
+ EXPECT_THAT(mLayer.outputLayerState.visibleNonTransparentRegion,
+ RegionEq(kFullBoundsNoRotation));
+ EXPECT_THAT(mLayer.outputLayerState.coveredRegion, RegionEq(kEmptyRegion));
+ EXPECT_THAT(mLayer.outputLayerState.outputSpaceVisibleRegion, RegionEq(kFullBoundsNoRotation));
}
TEST_F(OutputEnsureOutputLayerIfVisibleTest,
handlesUpdatingOutputLayerForOpaqueNonDirtyNotRotatedLayer) {
- mLayerFEState.isOpaque = true;
- mLayerFEState.contentDirty = false;
- mLayerFEState.geomLayerTransform = ui::Transform(TR_IDENT, 100, 200);
+ mLayer.layerFEState.isOpaque = true;
+ mLayer.layerFEState.contentDirty = false;
+ mLayer.layerFEState.geomLayerTransform = ui::Transform(TR_IDENT, 100, 200);
- EXPECT_CALL(mOutput, ensureOutputLayer(Eq(0u), Eq(mLayer), Eq(mLayerFE)))
- .WillOnce(Return(&mOutputLayer));
+ EXPECT_CALL(mOutput, ensureOutputLayer(Eq(0u), Eq(mLayer.layerFE)))
+ .WillOnce(Return(&mLayer.outputLayer));
- mOutput.ensureOutputLayerIfVisible(mLayer, mCoverageState);
+ ensureOutputLayerIfVisible();
EXPECT_THAT(mCoverageState.dirtyRegion, RegionEq(kLowerHalfBoundsNoRotation));
EXPECT_THAT(mCoverageState.aboveCoveredLayers, RegionEq(kFullBoundsNoRotation));
EXPECT_THAT(mCoverageState.aboveOpaqueLayers, RegionEq(kFullBoundsNoRotation));
- EXPECT_THAT(mOutputLayerState.visibleRegion, RegionEq(kFullBoundsNoRotation));
- EXPECT_THAT(mOutputLayerState.visibleNonTransparentRegion, RegionEq(kFullBoundsNoRotation));
- EXPECT_THAT(mOutputLayerState.coveredRegion, RegionEq(kEmptyRegion));
- EXPECT_THAT(mOutputLayerState.outputSpaceVisibleRegion, RegionEq(kFullBoundsNoRotation));
+ EXPECT_THAT(mLayer.outputLayerState.visibleRegion, RegionEq(kFullBoundsNoRotation));
+ EXPECT_THAT(mLayer.outputLayerState.visibleNonTransparentRegion,
+ RegionEq(kFullBoundsNoRotation));
+ EXPECT_THAT(mLayer.outputLayerState.coveredRegion, RegionEq(kEmptyRegion));
+ EXPECT_THAT(mLayer.outputLayerState.outputSpaceVisibleRegion, RegionEq(kFullBoundsNoRotation));
}
TEST_F(OutputEnsureOutputLayerIfVisibleTest,
handlesCreatingOutputLayerForOpaqueDirtyRotated90Layer) {
- mLayerFEState.isOpaque = true;
- mLayerFEState.contentDirty = true;
- mLayerFEState.geomLayerBounds = FloatRect{0, 0, 200, 100};
- mLayerFEState.geomLayerTransform = ui::Transform(TR_ROT_90, 100, 200);
- mOutputLayerState.visibleRegion = Region(Rect(0, 0, 100, 100));
- mOutputLayerState.coveredRegion = Region(Rect(100, 0, 200, 100));
+ mLayer.layerFEState.isOpaque = true;
+ mLayer.layerFEState.contentDirty = true;
+ mLayer.layerFEState.geomLayerBounds = FloatRect{0, 0, 200, 100};
+ mLayer.layerFEState.geomLayerTransform = ui::Transform(TR_ROT_90, 100, 200);
+ mLayer.outputLayerState.visibleRegion = Region(Rect(0, 0, 100, 100));
+ mLayer.outputLayerState.coveredRegion = Region(Rect(100, 0, 200, 100));
EXPECT_CALL(mOutput, getOutputLayerCount()).WillOnce(Return(0u));
- EXPECT_CALL(mOutput, ensureOutputLayer(Eq(std::nullopt), Eq(mLayer), Eq(mLayerFE)))
- .WillOnce(Return(&mOutputLayer));
+ EXPECT_CALL(mOutput, ensureOutputLayer(Eq(std::nullopt), Eq(mLayer.layerFE)))
+ .WillOnce(Return(&mLayer.outputLayer));
- mOutput.ensureOutputLayerIfVisible(mLayer, mCoverageState);
+ ensureOutputLayerIfVisible();
EXPECT_THAT(mCoverageState.dirtyRegion, RegionEq(kFullBoundsNoRotation));
EXPECT_THAT(mCoverageState.aboveCoveredLayers, RegionEq(kFullBoundsNoRotation));
EXPECT_THAT(mCoverageState.aboveOpaqueLayers, RegionEq(kFullBoundsNoRotation));
- EXPECT_THAT(mOutputLayerState.visibleRegion, RegionEq(kFullBoundsNoRotation));
- EXPECT_THAT(mOutputLayerState.visibleNonTransparentRegion, RegionEq(kFullBoundsNoRotation));
- EXPECT_THAT(mOutputLayerState.coveredRegion, RegionEq(kEmptyRegion));
- EXPECT_THAT(mOutputLayerState.outputSpaceVisibleRegion, RegionEq(kFullBoundsNoRotation));
+ EXPECT_THAT(mLayer.outputLayerState.visibleRegion, RegionEq(kFullBoundsNoRotation));
+ EXPECT_THAT(mLayer.outputLayerState.visibleNonTransparentRegion,
+ RegionEq(kFullBoundsNoRotation));
+ EXPECT_THAT(mLayer.outputLayerState.coveredRegion, RegionEq(kEmptyRegion));
+ EXPECT_THAT(mLayer.outputLayerState.outputSpaceVisibleRegion, RegionEq(kFullBoundsNoRotation));
}
TEST_F(OutputEnsureOutputLayerIfVisibleTest,
handlesUpdatingOutputLayerForOpaqueDirtyRotated90Layer) {
- mLayerFEState.isOpaque = true;
- mLayerFEState.contentDirty = true;
- mLayerFEState.geomLayerBounds = FloatRect{0, 0, 200, 100};
- mLayerFEState.geomLayerTransform = ui::Transform(TR_ROT_90, 100, 200);
- mOutputLayerState.visibleRegion = Region(Rect(0, 0, 100, 100));
- mOutputLayerState.coveredRegion = Region(Rect(100, 0, 200, 100));
+ mLayer.layerFEState.isOpaque = true;
+ mLayer.layerFEState.contentDirty = true;
+ mLayer.layerFEState.geomLayerBounds = FloatRect{0, 0, 200, 100};
+ mLayer.layerFEState.geomLayerTransform = ui::Transform(TR_ROT_90, 100, 200);
+ mLayer.outputLayerState.visibleRegion = Region(Rect(0, 0, 100, 100));
+ mLayer.outputLayerState.coveredRegion = Region(Rect(100, 0, 200, 100));
- EXPECT_CALL(mOutput, ensureOutputLayer(Eq(0u), Eq(mLayer), Eq(mLayerFE)))
- .WillOnce(Return(&mOutputLayer));
+ EXPECT_CALL(mOutput, ensureOutputLayer(Eq(0u), Eq(mLayer.layerFE)))
+ .WillOnce(Return(&mLayer.outputLayer));
- mOutput.ensureOutputLayerIfVisible(mLayer, mCoverageState);
+ ensureOutputLayerIfVisible();
EXPECT_THAT(mCoverageState.dirtyRegion, RegionEq(kFullBoundsNoRotation));
EXPECT_THAT(mCoverageState.aboveCoveredLayers, RegionEq(kFullBoundsNoRotation));
EXPECT_THAT(mCoverageState.aboveOpaqueLayers, RegionEq(kFullBoundsNoRotation));
- EXPECT_THAT(mOutputLayerState.visibleRegion, RegionEq(kFullBoundsNoRotation));
- EXPECT_THAT(mOutputLayerState.visibleNonTransparentRegion, RegionEq(kFullBoundsNoRotation));
- EXPECT_THAT(mOutputLayerState.coveredRegion, RegionEq(kEmptyRegion));
- EXPECT_THAT(mOutputLayerState.outputSpaceVisibleRegion, RegionEq(kFullBoundsNoRotation));
+ EXPECT_THAT(mLayer.outputLayerState.visibleRegion, RegionEq(kFullBoundsNoRotation));
+ EXPECT_THAT(mLayer.outputLayerState.visibleNonTransparentRegion,
+ RegionEq(kFullBoundsNoRotation));
+ EXPECT_THAT(mLayer.outputLayerState.coveredRegion, RegionEq(kEmptyRegion));
+ EXPECT_THAT(mLayer.outputLayerState.outputSpaceVisibleRegion, RegionEq(kFullBoundsNoRotation));
}
TEST_F(OutputEnsureOutputLayerIfVisibleTest,
handlesCreatingOutputLayerForOpaqueDirtyNotRotatedLayerRotatedOutput) {
- mLayerFEState.isOpaque = true;
- mLayerFEState.contentDirty = true;
- mLayerFEState.geomLayerTransform = ui::Transform(TR_IDENT, 100, 200);
+ mLayer.layerFEState.isOpaque = true;
+ mLayer.layerFEState.contentDirty = true;
+ mLayer.layerFEState.geomLayerTransform = ui::Transform(TR_IDENT, 100, 200);
mOutput.mState.viewport = Rect(0, 0, 300, 200);
mOutput.mState.transform = ui::Transform(TR_ROT_90, 200, 300);
EXPECT_CALL(mOutput, getOutputLayerCount()).WillOnce(Return(0u));
- EXPECT_CALL(mOutput, ensureOutputLayer(Eq(std::nullopt), Eq(mLayer), Eq(mLayerFE)))
- .WillOnce(Return(&mOutputLayer));
+ EXPECT_CALL(mOutput, ensureOutputLayer(Eq(std::nullopt), Eq(mLayer.layerFE)))
+ .WillOnce(Return(&mLayer.outputLayer));
- mOutput.ensureOutputLayerIfVisible(mLayer, mCoverageState);
+ ensureOutputLayerIfVisible();
EXPECT_THAT(mCoverageState.dirtyRegion, RegionEq(kFullBoundsNoRotation));
EXPECT_THAT(mCoverageState.aboveCoveredLayers, RegionEq(kFullBoundsNoRotation));
EXPECT_THAT(mCoverageState.aboveOpaqueLayers, RegionEq(kFullBoundsNoRotation));
- EXPECT_THAT(mOutputLayerState.visibleRegion, RegionEq(kFullBoundsNoRotation));
- EXPECT_THAT(mOutputLayerState.visibleNonTransparentRegion, RegionEq(kFullBoundsNoRotation));
- EXPECT_THAT(mOutputLayerState.coveredRegion, RegionEq(kEmptyRegion));
- EXPECT_THAT(mOutputLayerState.outputSpaceVisibleRegion, RegionEq(kFullBounds90Rotation));
+ EXPECT_THAT(mLayer.outputLayerState.visibleRegion, RegionEq(kFullBoundsNoRotation));
+ EXPECT_THAT(mLayer.outputLayerState.visibleNonTransparentRegion,
+ RegionEq(kFullBoundsNoRotation));
+ EXPECT_THAT(mLayer.outputLayerState.coveredRegion, RegionEq(kEmptyRegion));
+ EXPECT_THAT(mLayer.outputLayerState.outputSpaceVisibleRegion, RegionEq(kFullBounds90Rotation));
}
TEST_F(OutputEnsureOutputLayerIfVisibleTest,
handlesUpdatingOutputLayerForOpaqueDirtyNotRotatedLayerRotatedOutput) {
- mLayerFEState.isOpaque = true;
- mLayerFEState.contentDirty = true;
- mLayerFEState.geomLayerTransform = ui::Transform(TR_IDENT, 100, 200);
+ mLayer.layerFEState.isOpaque = true;
+ mLayer.layerFEState.contentDirty = true;
+ mLayer.layerFEState.geomLayerTransform = ui::Transform(TR_IDENT, 100, 200);
mOutput.mState.viewport = Rect(0, 0, 300, 200);
mOutput.mState.transform = ui::Transform(TR_ROT_90, 200, 300);
- EXPECT_CALL(mOutput, ensureOutputLayer(Eq(0u), Eq(mLayer), Eq(mLayerFE)))
- .WillOnce(Return(&mOutputLayer));
+ EXPECT_CALL(mOutput, ensureOutputLayer(Eq(0u), Eq(mLayer.layerFE)))
+ .WillOnce(Return(&mLayer.outputLayer));
- mOutput.ensureOutputLayerIfVisible(mLayer, mCoverageState);
+ ensureOutputLayerIfVisible();
EXPECT_THAT(mCoverageState.dirtyRegion, RegionEq(kFullBoundsNoRotation));
EXPECT_THAT(mCoverageState.aboveCoveredLayers, RegionEq(kFullBoundsNoRotation));
EXPECT_THAT(mCoverageState.aboveOpaqueLayers, RegionEq(kFullBoundsNoRotation));
- EXPECT_THAT(mOutputLayerState.visibleRegion, RegionEq(kFullBoundsNoRotation));
- EXPECT_THAT(mOutputLayerState.visibleNonTransparentRegion, RegionEq(kFullBoundsNoRotation));
- EXPECT_THAT(mOutputLayerState.coveredRegion, RegionEq(kEmptyRegion));
- EXPECT_THAT(mOutputLayerState.outputSpaceVisibleRegion, RegionEq(kFullBounds90Rotation));
+ EXPECT_THAT(mLayer.outputLayerState.visibleRegion, RegionEq(kFullBoundsNoRotation));
+ EXPECT_THAT(mLayer.outputLayerState.visibleNonTransparentRegion,
+ RegionEq(kFullBoundsNoRotation));
+ EXPECT_THAT(mLayer.outputLayerState.coveredRegion, RegionEq(kEmptyRegion));
+ EXPECT_THAT(mLayer.outputLayerState.outputSpaceVisibleRegion, RegionEq(kFullBounds90Rotation));
}
TEST_F(OutputEnsureOutputLayerIfVisibleTest,
@@ -1393,16 +1395,16 @@
arbitraryTransform.set(1, 1, -1, 1);
arbitraryTransform.set(0, 100);
- mLayerFEState.isOpaque = true;
- mLayerFEState.contentDirty = true;
- mLayerFEState.geomLayerBounds = FloatRect{0, 0, 100, 200};
- mLayerFEState.geomLayerTransform = arbitraryTransform;
+ mLayer.layerFEState.isOpaque = true;
+ mLayer.layerFEState.contentDirty = true;
+ mLayer.layerFEState.geomLayerBounds = FloatRect{0, 0, 100, 200};
+ mLayer.layerFEState.geomLayerTransform = arbitraryTransform;
EXPECT_CALL(mOutput, getOutputLayerCount()).WillOnce(Return(0u));
- EXPECT_CALL(mOutput, ensureOutputLayer(Eq(std::nullopt), Eq(mLayer), Eq(mLayerFE)))
- .WillOnce(Return(&mOutputLayer));
+ EXPECT_CALL(mOutput, ensureOutputLayer(Eq(std::nullopt), Eq(mLayer.layerFE)))
+ .WillOnce(Return(&mLayer.outputLayer));
- mOutput.ensureOutputLayerIfVisible(mLayer, mCoverageState);
+ ensureOutputLayerIfVisible();
const Region kRegion = Region(Rect(0, 0, 300, 300));
const Region kRegionClipped = Region(Rect(0, 0, 200, 300));
@@ -1411,25 +1413,25 @@
EXPECT_THAT(mCoverageState.aboveCoveredLayers, RegionEq(kRegion));
EXPECT_THAT(mCoverageState.aboveOpaqueLayers, RegionEq(kEmptyRegion));
- EXPECT_THAT(mOutputLayerState.visibleRegion, RegionEq(kRegion));
- EXPECT_THAT(mOutputLayerState.visibleNonTransparentRegion, RegionEq(kRegion));
- EXPECT_THAT(mOutputLayerState.coveredRegion, RegionEq(kEmptyRegion));
- EXPECT_THAT(mOutputLayerState.outputSpaceVisibleRegion, RegionEq(kRegionClipped));
+ EXPECT_THAT(mLayer.outputLayerState.visibleRegion, RegionEq(kRegion));
+ EXPECT_THAT(mLayer.outputLayerState.visibleNonTransparentRegion, RegionEq(kRegion));
+ EXPECT_THAT(mLayer.outputLayerState.coveredRegion, RegionEq(kEmptyRegion));
+ EXPECT_THAT(mLayer.outputLayerState.outputSpaceVisibleRegion, RegionEq(kRegionClipped));
}
TEST_F(OutputEnsureOutputLayerIfVisibleTest, coverageAccumulatesTest) {
- mLayerFEState.isOpaque = false;
- mLayerFEState.contentDirty = true;
- mLayerFEState.geomLayerTransform = ui::Transform(TR_IDENT, 100, 200);
+ mLayer.layerFEState.isOpaque = false;
+ mLayer.layerFEState.contentDirty = true;
+ mLayer.layerFEState.geomLayerTransform = ui::Transform(TR_IDENT, 100, 200);
mCoverageState.dirtyRegion = Region(Rect(0, 0, 500, 500));
mCoverageState.aboveCoveredLayers = Region(Rect(50, 0, 150, 200));
mCoverageState.aboveOpaqueLayers = Region(Rect(50, 0, 150, 200));
- EXPECT_CALL(mOutput, ensureOutputLayer(Eq(0u), Eq(mLayer), Eq(mLayerFE)))
- .WillOnce(Return(&mOutputLayer));
+ EXPECT_CALL(mOutput, ensureOutputLayer(Eq(0u), Eq(mLayer.layerFE)))
+ .WillOnce(Return(&mLayer.outputLayer));
- mOutput.ensureOutputLayerIfVisible(mLayer, mCoverageState);
+ ensureOutputLayerIfVisible();
const Region kExpectedDirtyRegion = Region(Rect(0, 0, 500, 500));
const Region kExpectedAboveCoveredRegion = Region(Rect(0, 0, 150, 200));
@@ -1442,28 +1444,29 @@
EXPECT_THAT(mCoverageState.aboveCoveredLayers, RegionEq(kExpectedAboveCoveredRegion));
EXPECT_THAT(mCoverageState.aboveOpaqueLayers, RegionEq(kExpectedAboveOpaqueRegion));
- EXPECT_THAT(mOutputLayerState.visibleRegion, RegionEq(kExpectedLayerVisibleRegion));
- EXPECT_THAT(mOutputLayerState.visibleNonTransparentRegion,
+ EXPECT_THAT(mLayer.outputLayerState.visibleRegion, RegionEq(kExpectedLayerVisibleRegion));
+ EXPECT_THAT(mLayer.outputLayerState.visibleNonTransparentRegion,
RegionEq(kExpectedLayerVisibleNonTransparentRegion));
- EXPECT_THAT(mOutputLayerState.coveredRegion, RegionEq(kExpectedLayerCoveredRegion));
- EXPECT_THAT(mOutputLayerState.outputSpaceVisibleRegion, RegionEq(kExpectedLayerVisibleRegion));
+ EXPECT_THAT(mLayer.outputLayerState.coveredRegion, RegionEq(kExpectedLayerCoveredRegion));
+ EXPECT_THAT(mLayer.outputLayerState.outputSpaceVisibleRegion,
+ RegionEq(kExpectedLayerVisibleRegion));
}
TEST_F(OutputEnsureOutputLayerIfVisibleTest, coverageAccumulatesWithShadowsTest) {
ui::Transform translate;
translate.set(50, 50);
- mLayerFEState.geomLayerTransform = translate;
- mLayerFEState.shadowRadius = 10.0f;
+ mLayer.layerFEState.geomLayerTransform = translate;
+ mLayer.layerFEState.shadowRadius = 10.0f;
mCoverageState.dirtyRegion = Region(Rect(0, 0, 500, 500));
// half of the layer including the casting shadow is covered and opaque
mCoverageState.aboveCoveredLayers = Region(Rect(40, 40, 100, 260));
mCoverageState.aboveOpaqueLayers = Region(Rect(40, 40, 100, 260));
- EXPECT_CALL(mOutput, ensureOutputLayer(Eq(0u), Eq(mLayer), Eq(mLayerFE)))
- .WillOnce(Return(&mOutputLayer));
+ EXPECT_CALL(mOutput, ensureOutputLayer(Eq(0u), Eq(mLayer.layerFE)))
+ .WillOnce(Return(&mLayer.outputLayer));
- mOutput.ensureOutputLayerIfVisible(mLayer, mCoverageState);
+ ensureOutputLayerIfVisible();
const Region kExpectedDirtyRegion = Region(Rect(0, 0, 500, 500));
const Region kExpectedAboveCoveredRegion = Region(Rect(40, 40, 160, 260));
@@ -1481,53 +1484,53 @@
EXPECT_THAT(mCoverageState.aboveCoveredLayers, RegionEq(kExpectedAboveCoveredRegion));
EXPECT_THAT(mCoverageState.aboveOpaqueLayers, RegionEq(kExpectedAboveOpaqueRegion));
- EXPECT_THAT(mOutputLayerState.visibleRegion, RegionEq(kExpectedLayerVisibleRegion));
- EXPECT_THAT(mOutputLayerState.visibleNonTransparentRegion,
+ EXPECT_THAT(mLayer.outputLayerState.visibleRegion, RegionEq(kExpectedLayerVisibleRegion));
+ EXPECT_THAT(mLayer.outputLayerState.visibleNonTransparentRegion,
RegionEq(kExpectedLayerVisibleNonTransparentRegion));
- EXPECT_THAT(mOutputLayerState.coveredRegion, RegionEq(kExpectedLayerCoveredRegion));
- EXPECT_THAT(mOutputLayerState.outputSpaceVisibleRegion,
+ EXPECT_THAT(mLayer.outputLayerState.coveredRegion, RegionEq(kExpectedLayerCoveredRegion));
+ EXPECT_THAT(mLayer.outputLayerState.outputSpaceVisibleRegion,
RegionEq(kExpectedoutputSpaceLayerVisibleRegion));
- EXPECT_THAT(mOutputLayerState.shadowRegion, RegionEq(kExpectedLayerShadowRegion));
+ EXPECT_THAT(mLayer.outputLayerState.shadowRegion, RegionEq(kExpectedLayerShadowRegion));
EXPECT_FALSE(kExpectedLayerVisibleRegion.subtract(kExpectedLayerShadowRegion).isEmpty());
}
TEST_F(OutputEnsureOutputLayerIfVisibleTest, shadowRegionOnlyTest) {
ui::Transform translate;
translate.set(50, 50);
- mLayerFEState.geomLayerTransform = translate;
- mLayerFEState.shadowRadius = 10.0f;
+ mLayer.layerFEState.geomLayerTransform = translate;
+ mLayer.layerFEState.shadowRadius = 10.0f;
mCoverageState.dirtyRegion = Region(Rect(0, 0, 500, 500));
// Casting layer is covered by an opaque region leaving only part of its shadow to be drawn
mCoverageState.aboveCoveredLayers = Region(Rect(40, 40, 150, 260));
mCoverageState.aboveOpaqueLayers = Region(Rect(40, 40, 150, 260));
- EXPECT_CALL(mOutput, ensureOutputLayer(Eq(0u), Eq(mLayer), Eq(mLayerFE)))
- .WillOnce(Return(&mOutputLayer));
+ EXPECT_CALL(mOutput, ensureOutputLayer(Eq(0u), Eq(mLayer.layerFE)))
+ .WillOnce(Return(&mLayer.outputLayer));
- mOutput.ensureOutputLayerIfVisible(mLayer, mCoverageState);
+ ensureOutputLayerIfVisible();
const Region kExpectedLayerVisibleRegion = Region(Rect(150, 40, 160, 260));
const Region kExpectedLayerShadowRegion =
Region(Rect(40, 40, 160, 260)).subtractSelf(Rect(50, 50, 150, 250));
- EXPECT_THAT(mOutputLayerState.visibleRegion, RegionEq(kExpectedLayerVisibleRegion));
- EXPECT_THAT(mOutputLayerState.shadowRegion, RegionEq(kExpectedLayerShadowRegion));
+ EXPECT_THAT(mLayer.outputLayerState.visibleRegion, RegionEq(kExpectedLayerVisibleRegion));
+ EXPECT_THAT(mLayer.outputLayerState.shadowRegion, RegionEq(kExpectedLayerShadowRegion));
EXPECT_TRUE(kExpectedLayerVisibleRegion.subtract(kExpectedLayerShadowRegion).isEmpty());
}
TEST_F(OutputEnsureOutputLayerIfVisibleTest, takesNotSoEarlyOutifLayerWithShadowIsCovered) {
ui::Transform translate;
translate.set(50, 50);
- mLayerFEState.geomLayerTransform = translate;
- mLayerFEState.shadowRadius = 10.0f;
+ mLayer.layerFEState.geomLayerTransform = translate;
+ mLayer.layerFEState.shadowRadius = 10.0f;
mCoverageState.dirtyRegion = Region(Rect(0, 0, 500, 500));
// Casting layer and its shadows are covered by an opaque region
mCoverageState.aboveCoveredLayers = Region(Rect(40, 40, 160, 260));
mCoverageState.aboveOpaqueLayers = Region(Rect(40, 40, 160, 260));
- mOutput.ensureOutputLayerIfVisible(mLayer, mCoverageState);
+ ensureOutputLayerIfVisible();
}
/*
@@ -1583,13 +1586,11 @@
struct Layer {
Layer() {
- EXPECT_CALL(mOutputLayer, getLayer()).WillRepeatedly(ReturnRef(mLayer));
EXPECT_CALL(mOutputLayer, getLayerFE()).WillRepeatedly(ReturnRef(mLayerFE));
- EXPECT_CALL(mLayer, getFEState()).WillRepeatedly(ReturnRef(mLayerFEState));
+ EXPECT_CALL(mLayerFE, getCompositionState()).WillRepeatedly(Return(&mLayerFEState));
}
StrictMock<mock::OutputLayer> mOutputLayer;
- StrictMock<mock::Layer> mLayer;
StrictMock<mock::LayerFE> mLayerFE;
LayerFECompositionState mLayerFEState;
};
@@ -3151,12 +3152,12 @@
struct OutputComposeSurfacesTest_HandlesProtectedContent : public OutputComposeSurfacesTest {
struct Layer {
Layer() {
- EXPECT_CALL(mOutputLayer, getLayer()).WillRepeatedly(ReturnRef(mLayer));
- EXPECT_CALL(mLayer, getFEState()).WillRepeatedly(ReturnRef(mLayerFEState));
+ EXPECT_CALL(mLayerFE, getCompositionState()).WillRepeatedly(Return(&mLayerFEState));
+ EXPECT_CALL(mOutputLayer, getLayerFE()).WillRepeatedly(ReturnRef(mLayerFE));
}
StrictMock<mock::OutputLayer> mOutputLayer;
- StrictMock<mock::Layer> mLayer;
+ StrictMock<mock::LayerFE> mLayerFE;
LayerFECompositionState mLayerFEState;
};
@@ -3323,13 +3324,11 @@
Layer() {
EXPECT_CALL(mOutputLayer, getState()).WillRepeatedly(ReturnRef(mOutputLayerState));
EXPECT_CALL(mOutputLayer, editState()).WillRepeatedly(ReturnRef(mOutputLayerState));
- EXPECT_CALL(mOutputLayer, getLayer()).WillRepeatedly(ReturnRef(mLayer));
EXPECT_CALL(mOutputLayer, getLayerFE()).WillRepeatedly(ReturnRef(mLayerFE));
- EXPECT_CALL(mLayer, getFEState()).WillRepeatedly(ReturnRef(mLayerFEState));
+ EXPECT_CALL(mLayerFE, getCompositionState()).WillRepeatedly(Return(&mLayerFEState));
}
StrictMock<mock::OutputLayer> mOutputLayer;
- StrictMock<mock::Layer> mLayer;
StrictMock<mock::LayerFE> mLayerFE;
LayerFECompositionState mLayerFEState;
impl::OutputLayerCompositionState mOutputLayerState;
@@ -3773,19 +3772,23 @@
}
TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBackgroundBlurRequests) {
+ InjectedLayer layer1;
+ InjectedLayer layer2;
+ InjectedLayer layer3;
+
// 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));
+ EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true));
+ EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(false));
+ EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true));
+ EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(false));
+ EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false));
+ EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(false));
- mLayer2FEState.backgroundBlurRadius = 10;
+ layer2.layerFEState.backgroundBlurRadius = 10;
- injectLayer(std::move(mOutputLayer1));
- injectLayer(std::move(mOutputLayer2));
- injectLayer(std::move(mOutputLayer3));
+ injectOutputLayer(layer1);
+ injectOutputLayer(layer2);
+ injectOutputLayer(layer3);
mOutput->editState().isEnabled = true;
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index f3fe159..6ff39b4 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -146,12 +146,12 @@
return mCompositionDisplay->getState().dataspace;
}
-void DisplayDevice::setLayerStack(uint32_t stack) {
+void DisplayDevice::setLayerStack(ui::LayerStack stack) {
mCompositionDisplay->setLayerStackFilter(stack, isPrimary());
}
-void DisplayDevice::setDisplaySize(const int newWidth, const int newHeight) {
- mCompositionDisplay->setBounds(ui::Size(newWidth, newHeight));
+void DisplayDevice::setDisplaySize(int width, int height) {
+ mCompositionDisplay->setBounds(ui::Size(width, height));
}
void DisplayDevice::setProjection(ui::Rotation orientation, Rect viewport, Rect frame) {
@@ -289,7 +289,7 @@
return mCompositionDisplay->getState().needsFiltering;
}
-uint32_t DisplayDevice::getLayerStack() const {
+ui::LayerStack DisplayDevice::getLayerStack() const {
return mCompositionDisplay->getState().layerStackId;
}
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 75c709e..f45feae 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -16,8 +16,6 @@
#pragma once
-#include <stdlib.h>
-
#include <memory>
#include <optional>
#include <string>
@@ -30,7 +28,7 @@
#include <math/mat4.h>
#include <renderengine/RenderEngine.h>
#include <system/window.h>
-#include <ui/DisplayInfo.h>
+#include <ui/DisplayState.h>
#include <ui/GraphicTypes.h>
#include <ui/HdrCapabilities.h>
#include <ui/Region.h>
@@ -80,12 +78,12 @@
// secure surfaces.
bool isSecure() const;
- int getWidth() const;
- int getHeight() const;
+ int getWidth() const;
+ int getHeight() const;
+ ui::Size getSize() const { return {getWidth(), getHeight()}; }
- void setLayerStack(uint32_t stack);
- void setDisplaySize(const int newWidth, const int newHeight);
-
+ void setLayerStack(ui::LayerStack);
+ void setDisplaySize(int width, int height);
void setProjection(ui::Rotation orientation, Rect viewport, Rect frame);
ui::Rotation getPhysicalOrientation() const { return mPhysicalOrientation; }
@@ -98,7 +96,7 @@
const Rect& getFrame() const;
const Rect& getSourceClip() const;
bool needsFiltering() const;
- uint32_t getLayerStack() const;
+ ui::LayerStack getLayerStack() const;
const std::optional<DisplayId>& getId() const;
const wp<IBinder>& getDisplayToken() const { return mDisplayToken; }
@@ -185,7 +183,7 @@
int32_t sequenceId = sNextSequenceId++;
std::optional<DisplayId> displayId;
sp<IGraphicBufferProducer> surface;
- uint32_t layerStack = NO_LAYER_STACK;
+ ui::LayerStack layerStack = ui::NO_LAYER_STACK;
Rect viewport;
Rect frame;
ui::Rotation orientation = ui::ROTATION_0;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index cedab59..effbed6 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -28,7 +28,6 @@
#include <android-base/stringprintf.h>
#include <binder/IPCThreadState.h>
#include <compositionengine/Display.h>
-#include <compositionengine/Layer.h>
#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/OutputLayer.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
@@ -117,7 +116,6 @@
mCurrentState.frameRateSelectionPriority = PRIORITY_UNSET;
mCurrentState.metadata = args.metadata;
mCurrentState.shadowRadius = 0.f;
- mCurrentState.frameRate = 0.f;
// drawing state & current state are identical
mDrawingState = mCurrentState;
@@ -416,7 +414,7 @@
win.bottom -= roundedCornersCrop.top;
}
-void Layer::latchBasicGeometry(compositionengine::LayerFECompositionState& compositionState) const {
+void Layer::prepareBasicGeometryCompositionState() {
const auto& drawingState{getDrawingState()};
const uint32_t layerStack = getLayerStack();
const auto alpha = static_cast<float>(getAlpha());
@@ -429,31 +427,28 @@
: Hwc2::IComposerClient::BlendMode::COVERAGE;
}
- // TODO(b/121291683): Instead of filling in a passed-in compositionState
- // structure, switch to Layer owning the structure and have
- // CompositionEngine be able to get a reference to it.
-
- compositionState.layerStackId =
+ auto* compositionState = editCompositionState();
+ compositionState->layerStackId =
(layerStack != ~0u) ? std::make_optional(layerStack) : std::nullopt;
- compositionState.internalOnly = getPrimaryDisplayOnly();
- compositionState.isVisible = isVisible();
- compositionState.isOpaque = opaque && !usesRoundedCorners && alpha == 1.f;
- compositionState.shadowRadius = mEffectiveShadowRadius;
+ compositionState->internalOnly = getPrimaryDisplayOnly();
+ compositionState->isVisible = isVisible();
+ compositionState->isOpaque = opaque && !usesRoundedCorners && alpha == 1.f;
+ compositionState->shadowRadius = mEffectiveShadowRadius;
- compositionState.contentDirty = contentDirty;
+ compositionState->contentDirty = contentDirty;
contentDirty = false;
- compositionState.geomLayerBounds = mBounds;
- compositionState.geomLayerTransform = getTransform();
- compositionState.geomInverseLayerTransform = compositionState.geomLayerTransform.inverse();
- compositionState.transparentRegionHint = getActiveTransparentRegion(drawingState);
+ compositionState->geomLayerBounds = mBounds;
+ compositionState->geomLayerTransform = getTransform();
+ compositionState->geomInverseLayerTransform = compositionState->geomLayerTransform.inverse();
+ compositionState->transparentRegionHint = getActiveTransparentRegion(drawingState);
- compositionState.blendMode = static_cast<Hwc2::IComposerClient::BlendMode>(blendMode);
- compositionState.alpha = alpha;
- compositionState.backgroundBlurRadius = drawingState.backgroundBlurRadius;
+ compositionState->blendMode = static_cast<Hwc2::IComposerClient::BlendMode>(blendMode);
+ compositionState->alpha = alpha;
+ compositionState->backgroundBlurRadius = drawingState.backgroundBlurRadius;
}
-void Layer::latchGeometry(compositionengine::LayerFECompositionState& compositionState) const {
+void Layer::prepareGeometryCompositionState() {
const auto& drawingState{getDrawingState()};
int type = drawingState.metadata.getInt32(METADATA_WINDOW_TYPE, 0);
@@ -469,45 +464,48 @@
}
}
- compositionState.geomBufferSize = getBufferSize(drawingState);
- compositionState.geomContentCrop = getBufferCrop();
- compositionState.geomCrop = getCrop(drawingState);
- compositionState.geomBufferTransform = getBufferTransform();
- compositionState.geomBufferUsesDisplayInverseTransform = getTransformToDisplayInverse();
- compositionState.geomUsesSourceCrop = usesSourceCrop();
- compositionState.isSecure = isSecure();
+ auto* compositionState = editCompositionState();
- compositionState.type = type;
- compositionState.appId = appId;
+ compositionState->geomBufferSize = getBufferSize(drawingState);
+ compositionState->geomContentCrop = getBufferCrop();
+ compositionState->geomCrop = getCrop(drawingState);
+ compositionState->geomBufferTransform = getBufferTransform();
+ compositionState->geomBufferUsesDisplayInverseTransform = getTransformToDisplayInverse();
+ compositionState->geomUsesSourceCrop = usesSourceCrop();
+ compositionState->isSecure = isSecure();
+
+ compositionState->type = type;
+ compositionState->appId = appId;
}
-void Layer::latchPerFrameState(compositionengine::LayerFECompositionState& compositionState) const {
+void Layer::preparePerFrameCompositionState() {
const auto& drawingState{getDrawingState()};
- compositionState.forceClientComposition = false;
+ auto* compositionState = editCompositionState();
- compositionState.isColorspaceAgnostic = isColorSpaceAgnostic();
- compositionState.dataspace = getDataSpace();
- compositionState.colorTransform = getColorTransform();
- compositionState.colorTransformIsIdentity = !hasColorTransform();
- compositionState.surfaceDamage = surfaceDamageRegion;
- compositionState.hasProtectedContent = isProtected();
+ compositionState->forceClientComposition = false;
+
+ compositionState->isColorspaceAgnostic = isColorSpaceAgnostic();
+ compositionState->dataspace = getDataSpace();
+ compositionState->colorTransform = getColorTransform();
+ compositionState->colorTransformIsIdentity = !hasColorTransform();
+ compositionState->surfaceDamage = surfaceDamageRegion;
+ compositionState->hasProtectedContent = isProtected();
const bool usesRoundedCorners = getRoundedCornerState().radius != 0.f;
const bool drawsShadows = mEffectiveShadowRadius != 0.f;
- compositionState.isOpaque =
+ compositionState->isOpaque =
isOpaque(drawingState) && !usesRoundedCorners && getAlpha() == 1.0_hf;
// Force client composition for special cases known only to the front-end.
if (isHdrY410() || usesRoundedCorners || drawsShadows) {
- compositionState.forceClientComposition = true;
+ compositionState->forceClientComposition = true;
}
}
-void Layer::latchCursorCompositionState(
- compositionengine::LayerFECompositionState& compositionState) const {
- // This gives us only the "orientation" component of the transform
+void Layer::prepareCursorCompositionState() {
const State& drawingState{getDrawingState()};
+ auto* compositionState = editCompositionState();
// Apply the layer's transform, followed by the display's global transform
// Here we're guaranteed that the layer's transform preserves rects
@@ -516,30 +514,50 @@
Rect bounds = reduce(win, getActiveTransparentRegion(drawingState));
Rect frame(getTransform().transform(bounds));
- compositionState.cursorFrame = frame;
+ compositionState->cursorFrame = frame;
+}
+
+sp<compositionengine::LayerFE> Layer::asLayerFE() const {
+ return const_cast<compositionengine::LayerFE*>(
+ static_cast<const compositionengine::LayerFE*>(this));
+}
+
+sp<compositionengine::LayerFE> Layer::getCompositionEngineLayerFE() const {
+ return nullptr;
+}
+
+compositionengine::LayerFECompositionState* Layer::editCompositionState() {
+ return nullptr;
+}
+
+const compositionengine::LayerFECompositionState* Layer::getCompositionState() const {
+ return nullptr;
}
bool Layer::onPreComposition(nsecs_t) {
return false;
}
-void Layer::latchCompositionState(compositionengine::LayerFECompositionState& compositionState,
- compositionengine::LayerFE::StateSubset subset) const {
+void Layer::prepareCompositionState(compositionengine::LayerFE::StateSubset subset) {
using StateSubset = compositionengine::LayerFE::StateSubset;
switch (subset) {
case StateSubset::BasicGeometry:
- latchBasicGeometry(compositionState);
+ prepareBasicGeometryCompositionState();
break;
case StateSubset::GeometryAndContent:
- latchBasicGeometry(compositionState);
- latchGeometry(compositionState);
- latchPerFrameState(compositionState);
+ prepareBasicGeometryCompositionState();
+ prepareGeometryCompositionState();
+ preparePerFrameCompositionState();
break;
case StateSubset::Content:
- latchPerFrameState(compositionState);
+ preparePerFrameCompositionState();
+ break;
+
+ case StateSubset::Cursor:
+ prepareCursorCompositionState();
break;
}
}
@@ -554,7 +572,7 @@
std::optional<compositionengine::LayerFE::LayerSettings> Layer::prepareClientComposition(
compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
- if (!getCompositionLayer()) {
+ if (!getCompositionState()) {
return {};
}
@@ -1245,7 +1263,7 @@
return true;
}
-bool Layer::setFrameRate(float frameRate) {
+bool Layer::setFrameRate(FrameRate frameRate) {
if (mCurrentState.frameRate == frameRate) {
return false;
}
@@ -1257,11 +1275,8 @@
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 {};
+Layer::FrameRate Layer::getFrameRate() const {
+ return getDrawingState().frameRate;
}
void Layer::deferTransactionUntil_legacy(const sp<Layer>& barrierLayer, uint64_t frameNumber) {
@@ -1422,7 +1437,7 @@
StringAppendF(&result, " %s\n", name.c_str());
const State& layerState(getDrawingState());
- const auto& compositionState = outputLayer->getState();
+ const auto& outputLayerState = outputLayer->getState();
if (layerState.zOrderRelativeOf != nullptr || mDrawingParent != nullptr) {
StringAppendF(&result, " rel %6d | ", layerState.z);
@@ -1431,13 +1446,10 @@
}
StringAppendF(&result, " %10d | ", mWindowType);
StringAppendF(&result, "%10s | ", toString(getCompositionType(displayDevice)).c_str());
- StringAppendF(&result, "%10s | ",
- toString(getCompositionLayer() ? compositionState.bufferTransform
- : static_cast<Hwc2::Transform>(0))
- .c_str());
- const Rect& frame = compositionState.displayFrame;
+ StringAppendF(&result, "%10s | ", toString(outputLayerState.bufferTransform).c_str());
+ const Rect& frame = outputLayerState.displayFrame;
StringAppendF(&result, "%4d %4d %4d %4d | ", frame.left, frame.top, frame.right, frame.bottom);
- const FloatRect& crop = compositionState.sourceCrop;
+ const FloatRect& crop = outputLayerState.sourceCrop;
StringAppendF(&result, "%6.1f %6.1f %6.1f %6.1f\n", crop.left, crop.top, crop.right,
crop.bottom);
@@ -2214,17 +2226,13 @@
return mDrawingState.inputInfo.token != nullptr;
}
-std::shared_ptr<compositionengine::Layer> Layer::getCompositionLayer() const {
- return nullptr;
-}
-
bool Layer::canReceiveInput() const {
return !isHiddenByPolicy();
}
compositionengine::OutputLayer* Layer::findOutputLayerForDisplay(
const sp<const DisplayDevice>& display) const {
- return display->getCompositionDisplay()->getOutputLayerForLayer(getCompositionLayer().get());
+ return display->getCompositionDisplay()->getOutputLayerForLayer(getCompositionEngineLayerFE());
}
Region Layer::debugGetVisibleRegionOnDefaultDisplay() const {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index da3df8f..de4a080 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -66,7 +66,6 @@
class LayerDebugInfo;
namespace compositionengine {
-class Layer;
class OutputLayer;
struct LayerFECompositionState;
}
@@ -94,7 +93,7 @@
uint32_t textureName;
};
-class Layer : public compositionengine::LayerFE {
+class Layer : public virtual RefBase, compositionengine::LayerFE {
static std::atomic<int32_t> sSequence;
static constexpr int32_t PRIORITY_UNSET = -1;
@@ -136,6 +135,34 @@
float radius = 0.0f;
};
+ // FrameRateCompatibility specifies how we should interpret the frame rate associated with
+ // the layer.
+ enum class FrameRateCompatibility {
+ Default, // Layer didn't specify any specific handling strategy
+
+ ExactOrMultiple, // Layer needs the exact frame rate (or a multiple of it) to present the
+ // content properly. Any other value will result in a pull down.
+
+ NoVote, // Layer doesn't have any requirements for the refresh rate and
+ // should not be considered when the display refresh rate is determined.
+ };
+
+ // Encapsulates the frame rate and compatibility of the layer. This information will be used
+ // when the display refresh rate is determined.
+ struct FrameRate {
+ float rate;
+ FrameRateCompatibility type;
+
+ FrameRate() : rate(0), type(FrameRateCompatibility::Default) {}
+ FrameRate(float rate, FrameRateCompatibility type) : rate(rate), type(type) {}
+
+ bool operator==(const FrameRate& other) const {
+ return rate == other.rate && type == other.type;
+ }
+
+ bool operator!=(const FrameRate& other) const { return !(*this == other); }
+ };
+
struct State {
Geometry active_legacy;
Geometry requested_legacy;
@@ -227,7 +254,7 @@
// Priority of the layer assigned by Window Manager.
int32_t frameRateSelectionPriority;
- float frameRate;
+ FrameRate frameRate;
};
explicit Layer(const LayerCreationArgs& args);
@@ -329,8 +356,8 @@
virtual bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/) { return false; };
virtual bool setCrop(const Rect& /*crop*/) { return false; };
virtual bool setFrame(const Rect& /*frame*/) { return false; };
- virtual bool setBuffer(const sp<GraphicBuffer>& /*buffer*/, nsecs_t /*postTime*/,
- nsecs_t /*desiredPresentTime*/,
+ virtual bool setBuffer(const sp<GraphicBuffer>& /*buffer*/, const sp<Fence>& /*acquireFence*/,
+ nsecs_t /*postTime*/, nsecs_t /*desiredPresentTime*/,
const client_cache_t& /*clientCacheId*/) {
return false;
};
@@ -345,6 +372,10 @@
return false;
};
virtual void forceSendCallbacks() {}
+ virtual bool addFrameEvent(const sp<Fence>& /*acquireFence*/, nsecs_t /*postedTime*/,
+ nsecs_t /*requestedPresentTime*/) {
+ return false;
+ }
virtual bool setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace);
virtual bool setColorSpaceAgnostic(const bool agnostic);
bool setShadowRadius(float shadowRadius);
@@ -362,7 +393,8 @@
// visually.
bool isLegacyDataSpace() const;
- virtual std::shared_ptr<compositionengine::Layer> getCompositionLayer() const;
+ virtual sp<compositionengine::LayerFE> getCompositionEngineLayerFE() const;
+ virtual compositionengine::LayerFECompositionState* editCompositionState();
// If we have received a new buffer this frame, we will pass its surface
// damage down to hardware composer. Otherwise, we must send a region with
@@ -507,6 +539,7 @@
virtual void updateCloneBufferInfo(){};
protected:
+ sp<compositionengine::LayerFE> asLayerFE() const;
sp<Layer> getClonedFrom() { return mClonedFrom != nullptr ? mClonedFrom.promote() : nullptr; }
bool isClone() { return mClonedFrom != nullptr; }
bool isClonedFromAlive() { return getClonedFrom() != nullptr; }
@@ -524,10 +557,9 @@
/*
* compositionengine::LayerFE overrides
*/
+ const compositionengine::LayerFECompositionState* getCompositionState() const override;
bool onPreComposition(nsecs_t) override;
- void latchCompositionState(compositionengine::LayerFECompositionState&,
- compositionengine::LayerFE::StateSubset subset) const override;
- void latchCursorCompositionState(compositionengine::LayerFECompositionState&) const override;
+ void prepareCompositionState(compositionengine::LayerFE::StateSubset subset) override;
std::optional<LayerSettings> prepareClientComposition(
compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
std::optional<LayerSettings> prepareShadowClientComposition(
@@ -537,9 +569,10 @@
const char* getDebugName() const override;
protected:
- void latchBasicGeometry(compositionengine::LayerFECompositionState& outState) const;
- void latchGeometry(compositionengine::LayerFECompositionState& outState) const;
- virtual void latchPerFrameState(compositionengine::LayerFECompositionState& outState) const;
+ void prepareBasicGeometryCompositionState();
+ void prepareGeometryCompositionState();
+ virtual void preparePerFrameCompositionState();
+ void prepareCursorCompositionState();
public:
virtual void setDefaultBufferSize(uint32_t /*w*/, uint32_t /*h*/) {}
@@ -567,6 +600,8 @@
// If a buffer was replaced this frame, release the former buffer
virtual void releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) { }
+ virtual void finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& /*glDoneFence*/,
+ const CompositorTiming& /*compositorTiming*/) {}
/*
* doTransaction - process the transaction. This is a good place to figure
* out which attributes of the surface have changed.
@@ -754,9 +789,8 @@
*/
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;
+ virtual bool setFrameRate(FrameRate frameRate);
+ virtual FrameRate getFrameRate() const;
protected:
// constant
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index d3d9d3a..682679c 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -155,7 +155,7 @@
Mutex::Autolock _l(mFlinger.mStateLock);
mLayer = mClient->getLayerUser(mIBinder);
- mLayer->setFrameRate(Layer::FRAME_RATE_NO_VOTE);
+ mLayer->setFrameRate(Layer::FrameRate(0, Layer::FrameRateCompatibility::NoVote));
// setting Layer's Z requires resorting layersSortedByZ
ssize_t idx = mFlinger.mCurrentState.layersSortedByZ.indexOf(mLayer);
@@ -208,7 +208,7 @@
const int32_t buttom = top + display->getHeight() / 32;
auto buffer = mBufferCache[refreshRate.fps];
- mLayer->setBuffer(buffer, 0, 0, {});
+ mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, {});
mLayer->setFrame(Rect(left, top, right, buttom));
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index b976523..9aada11 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -39,7 +39,7 @@
namespace {
bool isLayerActive(const Layer& layer, const LayerInfo& info, nsecs_t threshold) {
- if (layer.getFrameRate().has_value()) {
+ if (layer.getFrameRate().rate > 0) {
return layer.isVisible();
}
return layer.isVisible() && info.getLastUpdatedTime() >= threshold;
@@ -126,18 +126,27 @@
// 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});
+ const auto frameRate = layer->getFrameRate();
+ if (frameRate.rate > 0.f) {
+ const auto voteType = [&]() {
+ switch (frameRate.type) {
+ case Layer::FrameRateCompatibility::Default:
+ return LayerVoteType::ExplicitDefault;
+ case Layer::FrameRateCompatibility::ExactOrMultiple:
+ return LayerVoteType::ExplicitExactOrMultiple;
+ case Layer::FrameRateCompatibility::NoVote:
+ return LayerVoteType::NoVote;
+ }
+ }();
+ summary.push_back({layer->getName(), voteType, frameRate.rate, /* weight */ 1.0f});
} else if (recent) {
- frameRate = info->getRefreshRate(now);
- summary.push_back({layer->getName(), LayerVoteType::Heuristic, *frameRate,
+ summary.push_back({layer->getName(), LayerVoteType::Heuristic,
+ info->getRefreshRate(now),
/* weight */ 1.0f});
}
if (CC_UNLIKELY(mTraceEnabled)) {
- trace(weakLayer, round<int>(*frameRate));
+ trace(weakLayer, round<int>(frameRate.rate));
}
}
}
diff --git a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
index a6d2c74..ce085f4 100644
--- a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
@@ -40,7 +40,7 @@
namespace {
bool isLayerActive(const Layer& layer, const LayerInfoV2& info, nsecs_t threshold) {
- if (layer.getFrameRate().has_value()) {
+ if (layer.getFrameRate().rate > 0) {
return layer.isVisible();
}
return layer.isVisible() && info.getLastUpdatedTime() >= threshold;
@@ -63,13 +63,17 @@
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 explicitDefaultVoteTag = "LFPS ExplicitDefault" + name;
+ const auto explicitExactOrMultipleVoteTag = "LFPS ExplicitExactOrMultiple" + 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(explicitDefaultVoteTag.c_str(),
+ type == LayerHistory::LayerVoteType::ExplicitDefault ? fps : 0);
+ ATRACE_INT(explicitExactOrMultipleVoteTag.c_str(),
+ type == LayerHistory::LayerVoteType::ExplicitExactOrMultiple ? fps : 0);
ATRACE_INT(minVoteTag.c_str(), type == LayerHistory::LayerVoteType::Min ? 1 : 0);
ATRACE_INT(maxVoteTag.c_str(), type == LayerHistory::LayerVoteType::Max ? 1 : 0);
@@ -160,12 +164,18 @@
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);
+ const auto voteType = [&]() {
+ switch (frameRate.type) {
+ case Layer::FrameRateCompatibility::Default:
+ return LayerVoteType::ExplicitDefault;
+ case Layer::FrameRateCompatibility::ExactOrMultiple:
+ return LayerVoteType::ExplicitExactOrMultiple;
+ case Layer::FrameRateCompatibility::NoVote:
+ return LayerVoteType::NoVote;
}
+ }();
+ if (frameRate.rate > 0 || voteType == LayerVoteType::NoVote) {
+ info->setLayerVote(voteType, frameRate.rate);
} else {
info->resetLayerVote();
}
diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
index f309d4d..345b8f9 100644
--- a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
@@ -54,21 +54,40 @@
return mFrameTimes.back().queueTime >= getActiveLayerThreshold(now);
}
+bool LayerInfoV2::isFrameTimeValid(const FrameTimeData& frameTime) const {
+ return frameTime.queueTime >= std::chrono::duration_cast<std::chrono::nanoseconds>(
+ mFrameTimeValidSince.time_since_epoch())
+ .count();
+}
+
bool LayerInfoV2::isFrequent(nsecs_t now) const {
- // Assume layer is infrequent if too few present times have been recorded.
+ // If we know nothing about this layer we consider it as frequent as it might be the start
+ // of an animation.
if (mFrameTimes.size() < FREQUENT_LAYER_WINDOW_SIZE) {
- return false;
+ 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;
+ if (!isFrameTimeValid(*it)) {
+ return true;
+ }
+
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() < 2) {
+ return false;
+ }
+
+ if (!isFrameTimeValid(mFrameTimes.front())) {
+ return false;
+ }
+
if (mFrameTimes.size() < HISTORY_SIZE &&
mFrameTimes.back().queueTime - mFrameTimes.front().queueTime < HISTORY_TIME.count()) {
return false;
diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.h b/services/surfaceflinger/Scheduler/LayerInfoV2.h
index 564f05e..90f6310 100644
--- a/services/surfaceflinger/Scheduler/LayerInfoV2.h
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.h
@@ -82,12 +82,25 @@
// updated time, the updated time is the present time.
nsecs_t getLastUpdatedTime() const { return mLastUpdatedTime; }
- void clearHistory() { mFrameTimes.clear(); }
+ void clearHistory() {
+ // Mark mFrameTimeValidSince to now to ignore all previous frame times.
+ // We are not deleting the old frame to keep track of whether we should treat the first
+ // buffer as Max as we don't know anything about this layer or Min as this layer is
+ // posting infrequent updates.
+ mFrameTimeValidSince = std::chrono::steady_clock::now();
+ }
private:
+ // Used to store the layer timestamps
+ struct FrameTimeData {
+ nsecs_t presetTime; // desiredPresentTime, if provided
+ nsecs_t queueTime; // buffer queue time
+ };
+
bool isFrequent(nsecs_t now) const;
bool hasEnoughDataForHeuristic() const;
std::optional<float> calculateRefreshRateIfPossible();
+ bool isFrameTimeValid(const FrameTimeData&) const;
// Used for sanitizing the heuristic data
const nsecs_t mHighRefreshRatePeriod;
@@ -103,12 +116,9 @@
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;
+ std::chrono::time_point<std::chrono::steady_clock> mFrameTimeValidSince =
+ std::chrono::steady_clock::now();
static constexpr size_t HISTORY_SIZE = 90;
static constexpr std::chrono::nanoseconds HISTORY_TIME = 1s;
};
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index d2af912..0f55615 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -37,7 +37,8 @@
int explicitContentFramerate = 0;
for (const auto& layer : layers) {
const auto desiredRefreshRateRound = round<int>(layer.desiredRefreshRate);
- if (layer.vote == LayerVoteType::Explicit) {
+ if (layer.vote == LayerVoteType::ExplicitDefault ||
+ layer.vote == LayerVoteType::ExplicitExactOrMultiple) {
if (desiredRefreshRateRound > explicitContentFramerate) {
explicitContentFramerate = desiredRefreshRateRound;
}
@@ -94,7 +95,8 @@
int noVoteLayers = 0;
int minVoteLayers = 0;
int maxVoteLayers = 0;
- int explicitVoteLayers = 0;
+ int explicitDefaultVoteLayers = 0;
+ int explicitExactOrMultipleVoteLayers = 0;
for (const auto& layer : layers) {
if (layer.vote == LayerVoteType::NoVote)
noVoteLayers++;
@@ -102,8 +104,10 @@
minVoteLayers++;
else if (layer.vote == LayerVoteType::Max)
maxVoteLayers++;
- else if (layer.vote == LayerVoteType::Explicit)
- explicitVoteLayers++;
+ else if (layer.vote == LayerVoteType::ExplicitDefault)
+ explicitDefaultVoteLayers++;
+ else if (layer.vote == LayerVoteType::ExplicitExactOrMultiple)
+ explicitExactOrMultipleVoteLayers++;
}
// Only if all layers want Min we should return Min
@@ -112,7 +116,7 @@
}
// If we have some Max layers and no Explicit we should return Max
- if (maxVoteLayers > 0 && explicitVoteLayers == 0) {
+ if (maxVoteLayers > 0 && explicitDefaultVoteLayers + explicitExactOrMultipleVoteLayers == 0) {
return *mAvailableRefreshRates.back();
}
@@ -131,9 +135,22 @@
continue;
}
- // If we have Explicit layers, ignore the Hueristic ones
- if (explicitVoteLayers > 0 && layer.vote == LayerVoteType::Heuristic) {
- continue;
+ // Adjust the weight in case we have explicit layers. The priority is:
+ // - ExplicitExactOrMultiple
+ // - ExplicitDefault
+ // - Heuristic
+ auto weight = layer.weight;
+ if (explicitExactOrMultipleVoteLayers + explicitDefaultVoteLayers > 0) {
+ if (layer.vote == LayerVoteType::Heuristic) {
+ weight /= 2.f;
+ }
+ }
+
+ if (explicitExactOrMultipleVoteLayers > 0) {
+ if (layer.vote == LayerVoteType::Heuristic ||
+ layer.vote == LayerVoteType::ExplicitDefault) {
+ weight /= 2.f;
+ }
}
for (auto& [refreshRate, overallScore] : scores) {
@@ -152,10 +169,10 @@
static constexpr size_t MAX_FRAMES_TO_FIT = 10; // Stop calculating when score < 0.1
if (displayFramesRem == 0) {
// Layer desired refresh rate matches the display rate.
- layerScore = layer.weight * 1.0f;
+ layerScore = weight * 1.0f;
} else if (displayFramesQuot == 0) {
// Layer desired refresh rate is higher the display rate.
- layerScore = layer.weight *
+ layerScore = weight *
(static_cast<float>(layerPeriod) / static_cast<float>(displayPeriod)) *
(1.0f / (MAX_FRAMES_TO_FIT + 1));
} else {
@@ -168,11 +185,11 @@
iter++;
}
- layerScore = layer.weight * (1.0f / iter);
+ layerScore = 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);
+ ALOGV("%s (weight %.2f) %.2fHz gives %s score of %.2f", layer.name.c_str(), weight,
+ 1e9f / layerPeriod, refreshRate->name.c_str(), layerScore);
overallScore += layerScore;
}
}
@@ -199,12 +216,20 @@
const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicy() const {
std::lock_guard lock(mLock);
- return *mAvailableRefreshRates.front();
+ if (!mRefreshRateSwitching) {
+ return *mCurrentRefreshRate;
+ } else {
+ return *mAvailableRefreshRates.front();
+ }
}
const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicy() const {
std::lock_guard lock(mLock);
+ if (!mRefreshRateSwitching) {
+ return *mCurrentRefreshRate;
+ } else {
return *mAvailableRefreshRates.back();
+ }
}
const RefreshRate& RefreshRateConfigs::getCurrentRefreshRate() const {
@@ -217,14 +242,18 @@
mCurrentRefreshRate = &mRefreshRates.at(configId);
}
-RefreshRateConfigs::RefreshRateConfigs(const std::vector<InputConfig>& configs,
- HwcConfigIndexType currentHwcConfig) {
+RefreshRateConfigs::RefreshRateConfigs(bool refreshRateSwitching,
+ const std::vector<InputConfig>& configs,
+ HwcConfigIndexType currentHwcConfig)
+ : mRefreshRateSwitching(refreshRateSwitching) {
init(configs, currentHwcConfig);
}
RefreshRateConfigs::RefreshRateConfigs(
+ bool refreshRateSwitching,
const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
- HwcConfigIndexType currentConfigId) {
+ HwcConfigIndexType currentConfigId)
+ : mRefreshRateSwitching(refreshRateSwitching) {
std::vector<InputConfig> inputConfigs;
for (size_t configId = 0; configId < configs.size(); ++configId) {
auto configGroup = HwcConfigGroupType(configs[configId]->getConfigGroup());
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index c762efd..c4dea0d 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -94,13 +94,19 @@
// Returns true if config is allowed by the current policy.
bool isConfigAllowed(HwcConfigIndexType config) const EXCLUDES(mLock);
+ // 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
+ 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
+ ExplicitDefault, // Specific refresh rate that was provided by the app with Default
+ // compatibility
+ ExplicitExactOrMultiple // Specific refresh rate that was provided by the app with
+ // ExactOrMultiple compatibility
};
// Captures the layer requirements for a refresh rate. This will be used to determine the
@@ -161,9 +167,10 @@
nsecs_t vsyncPeriod = 0;
};
- RefreshRateConfigs(const std::vector<InputConfig>& configs,
+ RefreshRateConfigs(bool refreshRateSwitching, const std::vector<InputConfig>& configs,
HwcConfigIndexType currentHwcConfig);
- RefreshRateConfigs(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
+ RefreshRateConfigs(bool refreshRateSwitching,
+ const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
HwcConfigIndexType currentConfigId);
private:
@@ -201,6 +208,8 @@
const RefreshRate* mMinSupportedRefreshRate;
const RefreshRate* mMaxSupportedRefreshRate;
+ const bool mRefreshRateSwitching;
+
mutable std::mutex mLock;
};
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 258ce0a..bc4f805 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -64,7 +64,7 @@
std::unique_ptr<DispSync> createDispSync() {
// TODO (140302863) remove this and use the vsync_reactor system.
- if (property_get_bool("debug.sf.vsync_reactor", false)) {
+ if (property_get_bool("debug.sf.vsync_reactor", true)) {
// TODO (144707443) tune Predictor tunables.
static constexpr int default_rate = 60;
static constexpr auto initial_period =
@@ -408,7 +408,8 @@
"SurfaceView - "
"com.google.android.youtube/"
"com.google.android.apps.youtube.app.WatchWhileActivity#0") {
- layer->setFrameRate(vote);
+ layer->setFrameRate(
+ Layer::FrameRate(vote, Layer::FrameRateCompatibility::ExactOrMultiple));
}
}
}
@@ -529,6 +530,8 @@
using base::StringAppendF;
const char* const states[] = {"off", "on"};
+ const bool supported = mRefreshRateConfigs.refreshRateSwitchingSupported();
+ StringAppendF(&result, "+ Refresh rate switching: %s\n", states[supported]);
StringAppendF(&result, "+ Content detection: %s\n", states[mLayerHistory != nullptr]);
StringAppendF(&result, "+ Idle timer: %s\n",
@@ -562,7 +565,8 @@
bool Scheduler::layerHistoryHasClientSpecifiedFrameRate() {
for (const auto& layer : mFeatures.contentRequirements) {
- if (layer.vote == scheduler::RefreshRateConfigs::LayerVoteType::Explicit) {
+ if (layer.vote == scheduler::RefreshRateConfigs::LayerVoteType::ExplicitDefault ||
+ layer.vote == scheduler::RefreshRateConfigs::LayerVoteType::ExplicitExactOrMultiple) {
return true;
}
}
@@ -571,44 +575,35 @@
}
HwcConfigIndexType Scheduler::calculateRefreshRateType() {
- // This block of the code checks whether any layers used the SetFrameRate API. If they have,
- // their request should be honored regardless of whether the device has refresh rate switching
- // turned off.
- if (layerHistoryHasClientSpecifiedFrameRate()) {
- if (!mUseContentDetectionV2) {
- return mRefreshRateConfigs.getRefreshRateForContent(mFeatures.contentRequirements)
- .configId;
- } else {
- return mRefreshRateConfigs.getRefreshRateForContentV2(mFeatures.contentRequirements)
- .configId;
- }
+ if (!mRefreshRateConfigs.refreshRateSwitchingSupported()) {
+ return mRefreshRateConfigs.getCurrentRefreshRate().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 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 (mDisplayPowerTimer &&
- (!mFeatures.isDisplayPowerStateNormal ||
- mFeatures.displayPowerTimer == TimerState::Reset)) {
- return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
- }
+ 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 (mTouchTimer && mFeatures.touch == TouchState::Active) {
- 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 (mIdleTimer && mFeatures.idleTimer == TimerState::Expired) {
- return mRefreshRateConfigs.getMinRefreshRateByPolicy().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 (!mUseContentDetectionV2) {
- // If content detection is off we choose performance as we don't know the content fps.
+ // If content detection is off we choose performance as we don't know the content fps
if (mFeatures.contentDetection == ContentDetectionState::Off) {
- // TODO(b/148428554): Be careful to not always call this.
return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
}
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index e688415..b467f24 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -38,7 +38,7 @@
VSyncPredictor::VSyncPredictor(nsecs_t idealPeriod, size_t historySize,
size_t minimumSamplesForPrediction, uint32_t outlierTolerancePercent)
- : mTraceOn(property_get_bool("debug.sf.vsp_trace", false)),
+ : mTraceOn(property_get_bool("debug.sf.vsp_trace", true)),
kHistorySize(historySize),
kMinimumSamplesForPrediction(minimumSamplesForPrediction),
kOutlierTolerancePercent(std::min(outlierTolerancePercent, kMaxPercent)),
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e7c2dbc..c125b2c 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -45,6 +45,7 @@
#include <compositionengine/CompositionRefreshArgs.h>
#include <compositionengine/Display.h>
#include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/OutputLayer.h>
#include <compositionengine/RenderSurface.h>
#include <compositionengine/impl/OutputCompositionState.h>
@@ -61,8 +62,10 @@
#include <renderengine/RenderEngine.h>
#include <ui/ColorSpace.h>
#include <ui/DebugUtils.h>
+#include <ui/DisplayConfig.h>
#include <ui/DisplayInfo.h>
#include <ui/DisplayStatInfo.h>
+#include <ui/DisplayState.h>
#include <ui/GraphicBufferAllocator.h>
#include <ui/PixelFormat.h>
#include <ui/UiConfig.h>
@@ -115,6 +118,7 @@
#include "android-base/parseint.h"
#include "android-base/stringprintf.h"
+#include <android/configuration.h>
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/types.h>
@@ -182,6 +186,19 @@
bool mLocked;
};
+// TODO(b/141333600): Consolidate with HWC2::Display::Config::Builder::getDefaultDensity.
+constexpr float FALLBACK_DENSITY = ACONFIGURATION_DENSITY_TV / 160.f;
+
+float getDensityFromProperty(const char* property, bool required) {
+ char value[PROPERTY_VALUE_MAX];
+ const float density = property_get(property, value, nullptr) > 0 ? std::atof(value) : 0.f;
+ if (!density && required) {
+ ALOGE("%s must be defined as a build property", property);
+ return FALLBACK_DENSITY;
+ }
+ return density / 160.f;
+}
+
// Currently we only support V0_SRGB and DISPLAY_P3 as composition preference.
bool validateCompositionDataspace(Dataspace dataspace) {
return dataspace == Dataspace::V0_SRGB || dataspace == Dataspace::DISPLAY_P3;
@@ -249,7 +266,8 @@
mFrameTracer(std::make_unique<FrameTracer>()),
mEventQueue(mFactory.createMessageQueue()),
mCompositionEngine(mFactory.createCompositionEngine()),
- mPendingSyncInputWindows(false) {}
+ mInternalDisplayDensity(getDensityFromProperty("ro.sf.lcd_density", true)),
+ mEmulatedDisplayDensity(getDensityFromProperty("qemu.sf.lcd_density", false)) {}
SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipInitialization) {
ALOGI("SurfaceFlinger is starting");
@@ -538,6 +556,12 @@
readPersistentProperties();
mBootStage = BootStage::FINISHED;
+ if (mRefreshRateConfigs->refreshRateSwitchingSupported()) {
+ // set the refresh rate according to the policy
+ 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());
@@ -728,8 +752,56 @@
return NO_ERROR;
}
+status_t SurfaceFlinger::getDisplayState(const sp<IBinder>& displayToken, ui::DisplayState* state) {
+ if (!displayToken || !state) {
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock lock(mStateLock);
+
+ const auto display = getDisplayDeviceLocked(displayToken);
+ if (!display) {
+ return NAME_NOT_FOUND;
+ }
+
+ state->layerStack = display->getLayerStack();
+ state->orientation = display->getOrientation();
+
+ const Rect viewport = display->getViewport();
+ state->viewport = viewport.isValid() ? viewport.getSize() : display->getSize();
+
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::getDisplayInfo(const sp<IBinder>& displayToken, DisplayInfo* info) {
+ if (!displayToken || !info) {
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock lock(mStateLock);
+
+ const auto display = getDisplayDeviceLocked(displayToken);
+ if (!display) {
+ return NAME_NOT_FOUND;
+ }
+
+ if (display->isVirtual()) {
+ return INVALID_OPERATION;
+ }
+
+ if (mEmulatedDisplayDensity) {
+ info->density = mEmulatedDisplayDensity;
+ } else {
+ info->density = display->isPrimary() ? mInternalDisplayDensity : FALLBACK_DENSITY;
+ }
+
+ info->secure = display->isSecure();
+
+ return NO_ERROR;
+}
+
status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& displayToken,
- Vector<DisplayInfo>* configs) {
+ Vector<DisplayConfig>* configs) {
if (!displayToken || !configs) {
return BAD_VALUE;
}
@@ -741,78 +813,42 @@
return NAME_NOT_FOUND;
}
- // TODO: Not sure if display density should handled by SF any longer
- class Density {
- static float getDensityFromProperty(char const* propName) {
- char property[PROPERTY_VALUE_MAX];
- float density = 0.0f;
- if (property_get(propName, property, nullptr) > 0) {
- density = strtof(property, nullptr);
- }
- return density;
- }
- public:
- static float getEmuDensity() {
- return getDensityFromProperty("qemu.sf.lcd_density"); }
- static float getBuildDensity() {
- return getDensityFromProperty("ro.sf.lcd_density"); }
- };
+ const bool isInternal = (displayId == getInternalDisplayIdLocked());
configs->clear();
for (const auto& hwConfig : getHwComposer().getConfigs(*displayId)) {
- DisplayInfo info = DisplayInfo();
+ DisplayConfig config;
- float xdpi = hwConfig->getDpiX();
- float ydpi = hwConfig->getDpiY();
+ auto width = hwConfig->getWidth();
+ auto height = hwConfig->getHeight();
- info.w = hwConfig->getWidth();
- info.h = hwConfig->getHeight();
- // Default display viewport to display width and height
- info.viewportW = info.w;
- info.viewportH = info.h;
+ auto xDpi = hwConfig->getDpiX();
+ auto yDpi = hwConfig->getDpiY();
- if (displayId == getInternalDisplayIdLocked()) {
- // The density of the device is provided by a build property
- float density = Density::getBuildDensity() / 160.0f;
- if (density == 0) {
- // the build doesn't provide a density -- this is wrong!
- // use xdpi instead
- ALOGE("ro.sf.lcd_density must be defined as a build property");
- density = xdpi / 160.0f;
- }
- if (Density::getEmuDensity()) {
- // if "qemu.sf.lcd_density" is specified, it overrides everything
- xdpi = ydpi = density = Density::getEmuDensity();
- density /= 160.0f;
- }
- info.density = density;
-
- const auto display = getDefaultDisplayDeviceLocked();
- info.orientation = display->getOrientation();
-
- // This is for screenrecord
- const Rect viewport = display->getViewport();
- if (viewport.isValid()) {
- info.viewportW = uint32_t(viewport.getWidth());
- info.viewportH = uint32_t(viewport.getHeight());
- }
- info.layerStack = display->getLayerStack();
- } else {
- // TODO: where should this value come from?
- static const int TV_DENSITY = 213;
- info.density = TV_DENSITY / 160.0f;
-
- const auto display = getDisplayDeviceLocked(displayToken);
- info.layerStack = display->getLayerStack();
+ if (isInternal &&
+ (internalDisplayOrientation == ui::ROTATION_90 ||
+ internalDisplayOrientation == ui::ROTATION_270)) {
+ std::swap(width, height);
+ std::swap(xDpi, yDpi);
}
- info.xdpi = xdpi;
- info.ydpi = ydpi;
- info.fps = 1e9 / hwConfig->getVsyncPeriod();
+ config.resolution = ui::Size(width, height);
- const auto offset = mPhaseConfiguration->getOffsetsForRefreshRate(info.fps);
- info.appVsyncOffset = offset.late.app;
+ if (mEmulatedDisplayDensity) {
+ config.xDpi = mEmulatedDisplayDensity;
+ config.yDpi = mEmulatedDisplayDensity;
+ } else {
+ config.xDpi = xDpi;
+ config.yDpi = yDpi;
+ }
+
+ const nsecs_t period = hwConfig->getVsyncPeriod();
+ config.refreshRate = 1e9f / period;
+
+ const auto offsets = mPhaseConfiguration->getOffsetsForRefreshRate(config.refreshRate);
+ config.appVsyncOffset = offsets.late.app;
+ config.sfVsyncOffset = offsets.late.sf;
// This is how far in advance a buffer must be queued for
// presentation at a given time. If you want a buffer to appear
@@ -826,18 +862,9 @@
//
// We add an additional 1ms to allow for processing time and
// differences between the ideal and actual refresh rate.
- info.presentationDeadline = hwConfig->getVsyncPeriod() - offset.late.sf + 1000000;
+ config.presentationDeadline = period - config.sfVsyncOffset + 1000000;
- // All non-virtual displays are currently considered secure.
- info.secure = true;
-
- if (displayId == getInternalDisplayIdLocked() &&
- (internalDisplayOrientation == ui::ROTATION_90 ||
- internalDisplayOrientation == ui::ROTATION_270)) {
- std::swap(info.w, info.h);
- }
-
- configs->push_back(info);
+ configs->push_back(config);
}
return NO_ERROR;
@@ -1851,13 +1878,13 @@
refreshArgs.outputs.push_back(display->getCompositionDisplay());
}
mDrawingState.traverseInZOrder([&refreshArgs](Layer* layer) {
- auto compositionLayer = layer->getCompositionLayer();
- if (compositionLayer) refreshArgs.layers.push_back(compositionLayer);
+ if (auto layerFE = layer->getCompositionEngineLayerFE())
+ refreshArgs.layers.push_back(layerFE);
});
refreshArgs.layersWithQueuedFrames.reserve(mLayersWithQueuedFrames.size());
for (sp<Layer> layer : mLayersWithQueuedFrames) {
- auto compositionLayer = layer->getCompositionLayer();
- if (compositionLayer) refreshArgs.layersWithQueuedFrames.push_back(compositionLayer.get());
+ if (auto layerFE = layer->getCompositionEngineLayerFE())
+ refreshArgs.layersWithQueuedFrames.push_back(layerFE);
}
refreshArgs.repaintEverything = mRepaintEverything.exchange(false);
@@ -2010,12 +2037,10 @@
ATRACE_CALL();
ALOGV("postComposition");
- // Release any buffers which were replaced this frame
nsecs_t dequeueReadyTime = systemTime();
for (auto& layer : mLayersWithQueuedFrames) {
layer->releasePendingBuffer(dequeueReadyTime);
}
-
// |mStateLock| not needed as we are on the main thread
const auto displayDevice = getDefaultDisplayDeviceLocked();
@@ -2693,7 +2718,8 @@
auto currentConfig = HwcConfigIndexType(getHwComposer().getActiveConfigIndex(primaryDisplayId));
mRefreshRateConfigs =
- std::make_unique<scheduler::RefreshRateConfigs>(getHwComposer().getConfigs(
+ std::make_unique<scheduler::RefreshRateConfigs>(refresh_rate_switching(false),
+ getHwComposer().getConfigs(
primaryDisplayId),
currentConfig);
mRefreshRateStats =
@@ -3321,6 +3347,11 @@
layer->pushPendingState();
}
+ // Only set by BLAST adapter layers
+ if (what & layer_state_t::eProducerDisconnect) {
+ layer->onDisconnect();
+ }
+
if (what & layer_state_t::ePositionChanged) {
if (layer->setPosition(s.x, s.y)) {
flags |= eTraversalNeeded;
@@ -3528,7 +3559,9 @@
}
}
if (what & layer_state_t::eFrameRateChanged) {
- if (layer->setFrameRate(s.frameRate)) flags |= eTraversalNeeded;
+ if (layer->setFrameRate(
+ Layer::FrameRate(s.frameRate, Layer::FrameRateCompatibility::Default)))
+ 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
@@ -3570,7 +3603,8 @@
buffer = s.buffer;
}
if (buffer) {
- if (layer->setBuffer(buffer, postTime, desiredPresentTime, s.cachedBuffer)) {
+ if (layer->setBuffer(buffer, s.acquireFence, postTime, desiredPresentTime,
+ s.cachedBuffer)) {
flags |= eTraversalNeeded;
}
}
@@ -4415,8 +4449,13 @@
{
StringAppendF(&result, "Composition layers\n");
mDrawingState.traverseInZOrder([&](Layer* layer) {
- auto compositionLayer = layer->getCompositionLayer();
- if (compositionLayer) compositionLayer->dump(result);
+ auto* compositionState = layer->getCompositionState();
+ if (!compositionState) return;
+
+ android::base::StringAppendF(&result, "* Layer %p (%s)\n", layer,
+ layer->getDebugName() ? layer->getDebugName()
+ : "<unknown>");
+ compositionState->dump(result);
});
}
@@ -4607,7 +4646,9 @@
case GET_PHYSICAL_DISPLAY_TOKEN:
case GET_DISPLAY_COLOR_MODES:
case GET_DISPLAY_NATIVE_PRIMARIES:
+ case GET_DISPLAY_INFO:
case GET_DISPLAY_CONFIGS:
+ case GET_DISPLAY_STATE:
case GET_DISPLAY_STATS:
case GET_SUPPORTED_FRAME_TIMESTAMPS:
// Calling setTransactionState is safe, because you need to have been
@@ -4637,12 +4678,6 @@
}
return OK;
}
- // The following codes are deprecated and should never be allowed to access SF.
- case CONNECT_DISPLAY_UNUSED:
- case CREATE_GRAPHIC_BUFFER_ALLOC_UNUSED: {
- ALOGE("Attempting to access SurfaceFlinger with unused code: %u", code);
- return PERMISSION_DENIED;
- }
case CAPTURE_SCREEN_BY_ID: {
IPCThreadState* ipc = IPCThreadState::self();
const int uid = ipc->getCallingUid();
@@ -5674,19 +5709,26 @@
mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value,
display->getActiveConfig(), vsyncPeriod);
- auto configId = mScheduler->getPreferredConfigId();
- auto preferredRefreshRate = configId
- ? mRefreshRateConfigs->getRefreshRateFromConfigId(*configId)
- // NOTE: Choose the default config ID, if Scheduler doesn't have one in mind.
- : mRefreshRateConfigs->getRefreshRateFromConfigId(defaultConfig);
- ALOGV("trying to switch to Scheduler preferred config %d (%s)",
- preferredRefreshRate.configId.value(), preferredRefreshRate.name.c_str());
-
- if (isDisplayConfigAllowed(preferredRefreshRate.configId)) {
- ALOGV("switching to Scheduler preferred config %d", preferredRefreshRate.configId.value());
- setDesiredActiveConfig({preferredRefreshRate.configId, Scheduler::ConfigEvent::Changed});
+ if (mRefreshRateConfigs->refreshRateSwitchingSupported()) {
+ auto configId = mScheduler->getPreferredConfigId();
+ auto preferredRefreshRate = configId
+ ? mRefreshRateConfigs->getRefreshRateFromConfigId(*configId)
+ : mRefreshRateConfigs->getMinRefreshRateByPolicy();
+ ALOGV("trying to switch to Scheduler preferred config %d (%s)",
+ preferredRefreshRate.configId.value(), preferredRefreshRate.name.c_str());
+ if (isDisplayConfigAllowed(preferredRefreshRate.configId)) {
+ ALOGV("switching to Scheduler preferred config %d",
+ preferredRefreshRate.configId.value());
+ setDesiredActiveConfig(
+ {preferredRefreshRate.configId, Scheduler::ConfigEvent::Changed});
+ } else {
+ // Set the highest allowed config
+ setDesiredActiveConfig({mRefreshRateConfigs->getMaxRefreshRateByPolicy().configId,
+ Scheduler::ConfigEvent::Changed});
+ }
} else {
- LOG_ALWAYS_FATAL("Desired config not allowed: %d", preferredRefreshRate.configId.value());
+ ALOGV("switching to config %d", defaultConfig.value());
+ setDesiredActiveConfig({defaultConfig, Scheduler::ConfigEvent::Changed});
}
return NO_ERROR;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 4c8775d..ccf5794 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -434,13 +434,13 @@
float frameScale, bool childrenOnly) override;
status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats) override;
- status_t getDisplayConfigs(const sp<IBinder>& displayToken,
- Vector<DisplayInfo>* configs) override;
+ status_t getDisplayState(const sp<IBinder>& displayToken, ui::DisplayState*) override;
+ status_t getDisplayInfo(const sp<IBinder>& displayToken, DisplayInfo*) override;
+ status_t getDisplayConfigs(const sp<IBinder>& displayToken, Vector<DisplayConfig>*) override;
int getActiveConfig(const sp<IBinder>& displayToken) override;
- status_t getDisplayColorModes(const sp<IBinder>& displayToken,
- Vector<ui::ColorMode>* configs) override;
+ status_t getDisplayColorModes(const sp<IBinder>& displayToken, Vector<ui::ColorMode>*) override;
status_t getDisplayNativePrimaries(const sp<IBinder>& displayToken,
- ui::DisplayPrimaries &primaries);
+ ui::DisplayPrimaries&) override;
ui::ColorMode getActiveColorMode(const sp<IBinder>& displayToken) override;
status_t setActiveColorMode(const sp<IBinder>& displayToken, ui::ColorMode colorMode) override;
status_t getAutoLowLatencyModeSupport(const sp<IBinder>& displayToken,
@@ -1165,6 +1165,9 @@
sp<RegionSamplingThread> mRegionSamplingThread;
ui::DisplayPrimaries mInternalDisplayPrimaries;
+ const float mInternalDisplayDensity;
+ const float mEmulatedDisplayDensity;
+
sp<IInputFlinger> mInputFlinger;
InputWindowCommands mPendingInputWindowCommands GUARDED_BY(mStateLock);
// Should only be accessed by the main thread.
@@ -1181,7 +1184,7 @@
const sp<SetInputWindowsListener> mSetInputWindowsListener = new SetInputWindowsListener(this);
- bool mPendingSyncInputWindows GUARDED_BY(mStateLock);
+ bool mPendingSyncInputWindows GUARDED_BY(mStateLock) = false;
Hwc2::impl::PowerAdvisor mPowerAdvisor;
// This should only be accessed on the main thread.
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
index 45889a5..f9658a7 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -77,7 +77,7 @@
ISchedulerCallback& schedulerCallback) {
return std::make_unique<Scheduler>(std::move(setVSyncEnabled), configs, schedulerCallback,
property_get_bool("debug.sf.use_content_detection_v2",
- false));
+ true));
}
std::unique_ptr<SurfaceInterceptor> DefaultFactory::createSurfaceInterceptor(
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp
index 768074a..b4716eb 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.cpp
+++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp
@@ -226,6 +226,14 @@
return static_cast<int64_t>(defaultValue);
}
+bool refresh_rate_switching(bool defaultValue) {
+ auto temp = SurfaceFlingerProperties::refresh_rate_switching();
+ if (temp.has_value()) {
+ return *temp;
+ }
+ return defaultValue;
+}
+
int32_t set_idle_timer_ms(int32_t defaultValue) {
auto temp = SurfaceFlingerProperties::set_idle_timer_ms();
if (temp.has_value()) {
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h
index 5f88322..e394cca 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.h
+++ b/services/surfaceflinger/SurfaceFlingerProperties.h
@@ -73,6 +73,8 @@
int64_t color_space_agnostic_dataspace(
android::hardware::graphics::common::V1_2::Dataspace defaultValue);
+bool refresh_rate_switching(bool defaultValue);
+
int32_t set_idle_timer_ms(int32_t defaultValue);
int32_t set_touch_timer_ms(int32_t defaultValue);
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index fdf8a41..493a709 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -37,10 +37,11 @@
namespace impl {
-status_pull_atom_return_t TimeStats::pullAtomCallback(int32_t atom_tag,
- pulled_stats_event_list* data, void* cookie) {
+AStatsManager_PullAtomCallbackReturn TimeStats::pullAtomCallback(int32_t atom_tag,
+ AStatsEventList* data,
+ void* cookie) {
impl::TimeStats* timeStats = reinterpret_cast<impl::TimeStats*>(cookie);
- status_pull_atom_return_t result = STATS_PULL_SKIP;
+ AStatsManager_PullAtomCallbackReturn result = AStatsManager_PULL_SKIP;
if (atom_tag == android::util::SURFACEFLINGER_STATS_GLOBAL_INFO) {
result = timeStats->populateGlobalAtom(data);
} else if (atom_tag == android::util::SURFACEFLINGER_STATS_LAYER_INFO) {
@@ -54,15 +55,15 @@
return result;
}
-status_pull_atom_return_t TimeStats::populateGlobalAtom(pulled_stats_event_list* data) {
+AStatsManager_PullAtomCallbackReturn TimeStats::populateGlobalAtom(AStatsEventList* data) {
std::lock_guard<std::mutex> lock(mMutex);
if (mTimeStats.statsStart == 0) {
- return STATS_PULL_SKIP;
+ return AStatsManager_PULL_SKIP;
}
flushPowerTimeLocked();
- struct stats_event* event = mStatsDelegate->addStatsEventToPullData(data);
+ AStatsEvent* event = mStatsDelegate->addStatsEventToPullData(data);
mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_GLOBAL_INFO);
mStatsDelegate->statsEventWriteInt64(event, mTimeStats.totalFrames);
mStatsDelegate->statsEventWriteInt64(event, mTimeStats.missedFrames);
@@ -72,7 +73,7 @@
mStatsDelegate->statsEventBuild(event);
clearGlobalLocked();
- return STATS_PULL_SUCCESS;
+ return AStatsManager_PULL_SUCCESS;
}
namespace {
@@ -110,7 +111,7 @@
}
} // namespace
-status_pull_atom_return_t TimeStats::populateLayerAtom(pulled_stats_event_list* data) {
+AStatsManager_PullAtomCallbackReturn TimeStats::populateLayerAtom(AStatsEventList* data) {
std::lock_guard<std::mutex> lock(mMutex);
std::vector<TimeStatsHelper::TimeStatsLayer const*> dumpStats;
@@ -129,7 +130,7 @@
}
for (const auto& layer : dumpStats) {
- struct stats_event* event = mStatsDelegate->addStatsEventToPullData(data);
+ AStatsEvent* 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);
@@ -151,7 +152,7 @@
}
clearLayersLocked();
- return STATS_PULL_SUCCESS;
+ return AStatsManager_PULL_SUCCESS;
}
TimeStats::TimeStats() : TimeStats(nullptr, std::nullopt, std::nullopt) {}
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 7f58725..a428ef4 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -159,37 +159,38 @@
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 AStatsEvent* addStatsEventToPullData(AStatsEventList* data) {
+ return AStatsEventList_addStatsEvent(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);
+ AStatsManager_PullAtomCallback callback,
+ AStatsManager_PullAtomMetadata* metadata,
+ void* cookie) {
+ return AStatsManager_registerPullAtomCallback(atom_tag, callback, metadata, cookie);
}
virtual void unregisterStatsPullAtomCallback(int32_t atom_tag) {
- return unregister_stats_pull_atom_callback(atom_tag);
+ return AStatsManager_unregisterPullAtomCallback(atom_tag);
}
- virtual void statsEventSetAtomId(struct stats_event* event, uint32_t atom_id) {
- return stats_event_set_atom_id(event, atom_id);
+ virtual void statsEventSetAtomId(AStatsEvent* event, uint32_t atom_id) {
+ return AStatsEvent_setAtomId(event, atom_id);
}
- virtual void statsEventWriteInt64(struct stats_event* event, int64_t field) {
- return stats_event_write_int64(event, field);
+ virtual void statsEventWriteInt64(AStatsEvent* event, int64_t field) {
+ return AStatsEvent_writeInt64(event, field);
}
- virtual void statsEventWriteString8(struct stats_event* event, const char* field) {
- return stats_event_write_string8(event, field);
+ virtual void statsEventWriteString8(AStatsEvent* event, const char* field) {
+ return AStatsEvent_writeString(event, field);
}
- virtual void statsEventWriteByteArray(struct stats_event* event, const uint8_t* buf,
+ virtual void statsEventWriteByteArray(AStatsEvent* event, const uint8_t* buf,
size_t numBytes) {
- return stats_event_write_byte_array(event, buf, numBytes);
+ return AStatsEvent_writeByteArray(event, buf, numBytes);
}
- virtual void statsEventBuild(struct stats_event* event) { return stats_event_build(event); }
+ virtual void statsEventBuild(AStatsEvent* event) { return AStatsEvent_build(event); }
};
// For testing only for injecting custom dependencies.
TimeStats(std::unique_ptr<StatsEventDelegate> statsDelegate,
@@ -238,10 +239,11 @@
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);
+ static AStatsManager_PullAtomCallbackReturn pullAtomCallback(int32_t atom_tag,
+ AStatsEventList* data,
+ void* cookie);
+ AStatsManager_PullAtomCallbackReturn populateGlobalAtom(AStatsEventList* data);
+ AStatsManager_PullAtomCallbackReturn populateLayerAtom(AStatsEventList* data);
bool recordReadyLocked(int32_t layerId, TimeRecord* timeRecord);
void flushAvailableRecordsToStatsLocked(int32_t layerId);
void flushPowerTimeLocked();
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index 1c910aa..e2f85cc 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -114,8 +114,14 @@
StringAppendF(&result, "totalP2PTime = %" PRId64 " ms\n", presentToPresent.totalTime());
StringAppendF(&result, "presentToPresent histogram is as below:\n");
result.append(presentToPresent.toString());
+ const float averageFrameDuration = frameDuration.averageTime();
+ StringAppendF(&result, "averageFrameDuration = %.3f ms\n",
+ std::isnan(averageFrameDuration) ? 0.0f : averageFrameDuration);
StringAppendF(&result, "frameDuration histogram is as below:\n");
result.append(frameDuration.toString());
+ const float averageRenderEngineTiming = renderEngineTiming.averageTime();
+ StringAppendF(&result, "averageRenderEngineTiming = %.3f ms\n",
+ std::isnan(averageRenderEngineTiming) ? 0.0f : averageRenderEngineTiming);
StringAppendF(&result, "renderEngineTiming histogram is as below:\n");
result.append(renderEngineTiming.toString());
const auto dumpStats = generateDumpStats(maxLayers);
diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
index daa67ae..0cdff8f 100644
--- a/services/surfaceflinger/TransactionCompletedThread.cpp
+++ b/services/surfaceflinger/TransactionCompletedThread.cpp
@@ -237,9 +237,13 @@
// destroyed the client side is dead and there won't be anyone to send the callback to.
sp<IBinder> surfaceControl = handle->surfaceControl.promote();
if (surfaceControl) {
+ FrameEventHistoryStats eventStats(handle->frameNumber,
+ handle->gpuCompositionDoneFence->getSnapshot().fence,
+ handle->compositorTiming, handle->refreshStartTime,
+ handle->dequeueReadyTime);
transactionStats->surfaceStats.emplace_back(surfaceControl, handle->acquireTime,
handle->previousReleaseFence,
- handle->transformHint);
+ handle->transformHint, eventStats);
}
return NO_ERROR;
}
diff --git a/services/surfaceflinger/TransactionCompletedThread.h b/services/surfaceflinger/TransactionCompletedThread.h
index 12ea8fe..f50147a 100644
--- a/services/surfaceflinger/TransactionCompletedThread.h
+++ b/services/surfaceflinger/TransactionCompletedThread.h
@@ -45,6 +45,11 @@
nsecs_t acquireTime = -1;
nsecs_t latchTime = -1;
uint32_t transformHint = 0;
+ std::shared_ptr<FenceTime> gpuCompositionDoneFence{FenceTime::NO_FENCE};
+ CompositorTiming compositorTiming;
+ nsecs_t refreshStartTime = 0;
+ nsecs_t dequeueReadyTime = 0;
+ uint64_t frameNumber = 0;
};
class TransactionCompletedThread {
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index 0653959..ed2b220 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -301,6 +301,18 @@
prop_name: "ro.surface_flinger.display_primary_white"
}
+# refreshRateSwitching indicates whether SurfaceFlinger should use refresh rate
+# switching on the device, e.g. to switch between 60 and 90 Hz. The settings
+# below that are related to refresh rate switching will only have an effect if
+# refresh_rate_switching is enabled.
+prop {
+ api_name: "refresh_rate_switching"
+ type: Boolean
+ scope: System
+ access: Readonly
+ prop_name: "ro.surface_flinger.refresh_rate_switching"
+}
+
prop {
api_name: "set_idle_timer_ms"
type: Integer
diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
index 1adab84..d24ad18 100644
--- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
+++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
@@ -73,6 +73,10 @@
enum_values: "ORIENTATION_0|ORIENTATION_90|ORIENTATION_180|ORIENTATION_270"
}
prop {
+ api_name: "refresh_rate_switching"
+ prop_name: "ro.surface_flinger.refresh_rate_switching"
+ }
+ prop {
api_name: "running_without_sync_framework"
prop_name: "ro.surface_flinger.running_without_sync_framework"
}
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index f339ab0..507d28b 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -1,20 +1,15 @@
-#include <algorithm>
-#include <functional>
-#include <limits>
-#include <ostream>
-
#include <gtest/gtest.h>
-
#include <gui/ISurfaceComposer.h>
#include <gui/LayerDebugInfo.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
-
#include <private/android_filesystem_config.h>
#include <private/gui/ComposerService.h>
-#include <ui/DisplayInfo.h>
+#include <ui/DisplayConfig.h>
#include <utils/String8.h>
+#include <functional>
+
namespace android {
using Transaction = SurfaceComposerClient::Transaction;
@@ -67,14 +62,13 @@
mDisplay = SurfaceComposerClient::getInternalDisplayToken();
ASSERT_FALSE(mDisplay == nullptr);
- DisplayInfo info;
- ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(mDisplay, &info));
- const ssize_t displayWidth = info.w;
- const ssize_t displayHeight = info.h;
+ DisplayConfig config;
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(mDisplay, &config));
// Background surface
mBGSurfaceControl =
- mComposerClient->createSurface(SURFACE_NAME, displayWidth, displayHeight,
+ mComposerClient->createSurface(SURFACE_NAME, config.resolution.getWidth(),
+ config.resolution.getHeight(),
PIXEL_FORMAT_RGBA_8888, 0);
ASSERT_TRUE(mBGSurfaceControl != nullptr);
ASSERT_TRUE(mBGSurfaceControl->isValid());
@@ -188,10 +182,10 @@
const auto display = SurfaceComposerClient::getInternalDisplayToken();
ASSERT_TRUE(display != nullptr);
- DisplayInfo info;
- ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
+ DisplayConfig config;
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
- Vector<DisplayInfo> configs;
+ Vector<DisplayConfig> configs;
ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs));
ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveConfig(display));
@@ -255,17 +249,6 @@
ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, false));
}
-TEST_F(CredentialsTest, DISABLED_DestroyDisplayTest) {
- setupVirtualDisplay();
-
- DisplayInfo info;
- ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(mVirtualDisplay, &info));
- SurfaceComposerClient::destroyDisplay(mVirtualDisplay);
- // This test currently fails. TODO(b/112002626): Find a way to properly create
- // a display in the test environment, so that destroy display can remove it.
- ASSERT_EQ(NAME_NOT_FOUND, SurfaceComposerClient::getDisplayInfo(mVirtualDisplay, &info));
-}
-
TEST_F(CredentialsTest, CaptureTest) {
const auto display = SurfaceComposerClient::getInternalDisplayToken();
std::function<status_t()> condition = [=]() {
diff --git a/services/surfaceflinger/tests/DisplayConfigs_test.cpp b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
index 3aa4474..0ed2ffb 100644
--- a/services/surfaceflinger/tests/DisplayConfigs_test.cpp
+++ b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
@@ -46,24 +46,25 @@
&initialMin, &initialMax);
ASSERT_EQ(res, NO_ERROR);
- Vector<DisplayInfo> configs;
+ Vector<DisplayConfig> configs;
res = SurfaceComposerClient::getDisplayConfigs(mDisplayToken, &configs);
ASSERT_EQ(res, NO_ERROR);
for (size_t i = 0; i < configs.size(); i++) {
- res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, i, configs[i].fps,
- configs[i].fps);
+ res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, i,
+ configs[i].refreshRate,
+ configs[i].refreshRate);
ASSERT_EQ(res, NO_ERROR);
int defaultConfig;
- float minFps;
- float maxFps;
+ float minRefreshRate;
+ float maxRefreshRate;
res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken, &defaultConfig,
- &minFps, &maxFps);
+ &minRefreshRate, &maxRefreshRate);
ASSERT_EQ(res, NO_ERROR);
ASSERT_EQ(defaultConfig, i);
- ASSERT_EQ(minFps, configs[i].fps);
- ASSERT_EQ(maxFps, configs[i].fps);
+ ASSERT_EQ(minRefreshRate, configs[i].refreshRate);
+ ASSERT_EQ(maxRefreshRate, configs[i].refreshRate);
}
res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, initialDefaultConfig,
diff --git a/services/surfaceflinger/tests/IPC_test.cpp b/services/surfaceflinger/tests/IPC_test.cpp
index 8a756a6..4023c66 100644
--- a/services/surfaceflinger/tests/IPC_test.cpp
+++ b/services/surfaceflinger/tests/IPC_test.cpp
@@ -14,24 +14,20 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
-
#include <binder/IInterface.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
-
+#include <gtest/gtest.h>
#include <gui/ISurfaceComposer.h>
#include <gui/LayerState.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
+#include <ui/DisplayConfig.h>
+#include <utils/String8.h>
#include <limits>
-#include <ui/DisplayInfo.h>
-
-#include <utils/String8.h>
-
#include "BufferGenerator.h"
#include "utils/CallbackUtils.h"
#include "utils/ColorUtils.h"
@@ -231,10 +227,10 @@
ASSERT_EQ(NO_ERROR, mClient->initCheck());
mPrimaryDisplay = mClient->getInternalDisplayToken();
- DisplayInfo info;
- mClient->getDisplayInfo(mPrimaryDisplay, &info);
- mDisplayWidth = info.w;
- mDisplayHeight = info.h;
+ DisplayConfig config;
+ mClient->getActiveDisplayConfig(mPrimaryDisplay, &config);
+ mDisplayWidth = config.resolution.getWidth();
+ mDisplayHeight = config.resolution.getHeight();
Transaction setupTransaction;
setupTransaction.setDisplayLayerStack(mPrimaryDisplay, 0);
diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h
index f7a6d96..5eb1739 100644
--- a/services/surfaceflinger/tests/LayerTransactionTest.h
+++ b/services/surfaceflinger/tests/LayerTransactionTest.h
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#ifndef ANDROID_LAYER_TRANSACTION_TEST_H
-#define ANDROID_LAYER_TRANSACTION_TEST_H
+
+#pragma once
#include <gtest/gtest.h>
-
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
#include <hardware/hwcomposer_defs.h>
#include <private/gui/ComposerService.h>
-
-#include <ui/DisplayInfo.h>
+#include <ui/DisplayConfig.h>
#include "BufferGenerator.h"
#include "utils/ScreenshotUtils.h"
@@ -255,18 +253,16 @@
mDisplay = mClient->getInternalDisplayToken();
ASSERT_FALSE(mDisplay == nullptr) << "failed to get display";
- // get display width/height
- DisplayInfo info;
- ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(mDisplay, &info));
- mDisplayWidth = info.w;
- mDisplayHeight = info.h;
- mDisplayRect =
- Rect(static_cast<int32_t>(mDisplayWidth), static_cast<int32_t>(mDisplayHeight));
+ DisplayConfig config;
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(mDisplay, &config));
+ mDisplayRect = Rect(config.resolution);
+ mDisplayWidth = mDisplayRect.getWidth();
+ mDisplayHeight = mDisplayRect.getHeight();
// After a new buffer is queued, SurfaceFlinger is notified and will
// latch the new buffer on next vsync. Let's heuristically wait for 3
// vsyncs.
- mBufferPostDelay = int32_t(1e6 / info.fps) * 3;
+ mBufferPostDelay = static_cast<int32_t>(1e6 / config.refreshRate) * 3;
mDisplayLayerStack = 0;
@@ -295,6 +291,5 @@
friend class LayerRenderPathTestHarness;
};
-} // namespace android
-#endif
+} // namespace android
diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp
index 0459386..a1c4128 100644
--- a/services/surfaceflinger/tests/LayerUpdate_test.cpp
+++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp
@@ -36,14 +36,13 @@
const auto display = SurfaceComposerClient::getInternalDisplayToken();
ASSERT_FALSE(display == nullptr);
- DisplayInfo info;
- ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
-
- ssize_t displayWidth = info.w;
- ssize_t displayHeight = info.h;
+ DisplayConfig config;
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ const ui::Size& resolution = config.resolution;
// Background surface
- mBGSurfaceControl = createLayer(String8("BG Test Surface"), displayWidth, displayHeight, 0);
+ mBGSurfaceControl = createLayer(String8("BG Test Surface"), resolution.getWidth(),
+ resolution.getHeight(), 0);
ASSERT_TRUE(mBGSurfaceControl != nullptr);
ASSERT_TRUE(mBGSurfaceControl->isValid());
TransactionUtils::fillSurfaceRGBA8(mBGSurfaceControl, 63, 63, 195);
@@ -73,7 +72,8 @@
.show(mFGSurfaceControl);
t.setLayer(mSyncSurfaceControl, INT32_MAX - 1)
- .setPosition(mSyncSurfaceControl, displayWidth - 2, displayHeight - 2)
+ .setPosition(mSyncSurfaceControl, resolution.getWidth() - 2,
+ resolution.getHeight() - 2)
.show(mSyncSurfaceControl);
});
}
diff --git a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
index e525e2a..c9fdc3b 100644
--- a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
+++ b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
@@ -18,6 +18,8 @@
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#include <ui/DisplayState.h>
+
#include "LayerTransactionTest.h"
namespace android {
@@ -34,12 +36,14 @@
ASSERT_EQ(NO_ERROR, mClient->initCheck());
mMainDisplay = SurfaceComposerClient::getInternalDisplayToken();
- SurfaceComposerClient::getDisplayInfo(mMainDisplay, &mMainDisplayInfo);
+ SurfaceComposerClient::getDisplayState(mMainDisplay, &mMainDisplayState);
+ SurfaceComposerClient::getActiveDisplayConfig(mMainDisplay, &mMainDisplayConfig);
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&mProducer, &consumer);
consumer->setConsumerName(String8("Virtual disp consumer"));
- consumer->setDefaultBufferSize(mMainDisplayInfo.w, mMainDisplayInfo.h);
+ consumer->setDefaultBufferSize(mMainDisplayConfig.resolution.getWidth(),
+ mMainDisplayConfig.resolution.getHeight());
}
virtual void TearDown() {
@@ -48,14 +52,14 @@
mColorLayer = 0;
}
- void createDisplay(const Rect& layerStackRect, uint32_t layerStack) {
+ void createDisplay(const ui::Size& layerStackSize, uint32_t layerStack) {
mVirtualDisplay =
SurfaceComposerClient::createDisplay(String8("VirtualDisplay"), false /*secure*/);
asTransaction([&](Transaction& t) {
t.setDisplaySurface(mVirtualDisplay, mProducer);
t.setDisplayLayerStack(mVirtualDisplay, layerStack);
- t.setDisplayProjection(mVirtualDisplay, mMainDisplayInfo.orientation, layerStackRect,
- Rect(mMainDisplayInfo.w, mMainDisplayInfo.h));
+ t.setDisplayProjection(mVirtualDisplay, mMainDisplayState.orientation,
+ Rect(layerStackSize), Rect(mMainDisplayConfig.resolution));
});
}
@@ -76,7 +80,8 @@
});
}
- DisplayInfo mMainDisplayInfo;
+ ui::DisplayState mMainDisplayState;
+ DisplayConfig mMainDisplayConfig;
sp<IBinder> mMainDisplay;
sp<IBinder> mVirtualDisplay;
sp<IGraphicBufferProducer> mProducer;
@@ -85,7 +90,7 @@
};
TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInVirtualDisplay) {
- createDisplay({mMainDisplayInfo.viewportW, mMainDisplayInfo.viewportH}, 1 /* layerStack */);
+ createDisplay(mMainDisplayState.viewport, 1 /* layerStack */);
createColorLayer(1 /* layerStack */);
asTransaction([&](Transaction& t) { t.setPosition(mColorLayer, 10, 10); });
@@ -108,7 +113,7 @@
// Assumption here is that the new mirrored display has the same viewport as the
// primary display that it is mirroring.
- createDisplay({mMainDisplayInfo.viewportW, mMainDisplayInfo.viewportH}, 0 /* layerStack */);
+ createDisplay(mMainDisplayState.viewport, 0 /* layerStack */);
createColorLayer(0 /* layerStack */);
asTransaction([&](Transaction& t) { t.setPosition(mColorLayer, 10, 10); });
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 4a2ab7c..0e7eba8 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -20,18 +20,13 @@
#include <frameworks/native/cmds/surfacereplayer/proto/src/trace.pb.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
-
#include <gtest/gtest.h>
-
-#include <android/native_window.h>
-
#include <gui/ISurfaceComposer.h>
#include <gui/LayerState.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
-
#include <private/gui/ComposerService.h>
-#include <ui/DisplayInfo.h>
+#include <ui/DisplayConfig.h>
#include <fstream>
#include <random>
@@ -271,21 +266,21 @@
const auto display = SurfaceComposerClient::getInternalDisplayToken();
ASSERT_FALSE(display == nullptr);
- DisplayInfo info;
- ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
-
- ssize_t displayWidth = info.w;
- ssize_t displayHeight = info.h;
+ DisplayConfig config;
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ const ui::Size& resolution = config.resolution;
// Background surface
- mBGSurfaceControl = mComposerClient->createSurface(String8(TEST_BG_SURFACE_NAME), displayWidth,
- displayHeight, PIXEL_FORMAT_RGBA_8888, 0);
+ mBGSurfaceControl =
+ mComposerClient->createSurface(String8(TEST_BG_SURFACE_NAME), resolution.getWidth(),
+ resolution.getHeight(), PIXEL_FORMAT_RGBA_8888, 0);
ASSERT_TRUE(mBGSurfaceControl != nullptr);
ASSERT_TRUE(mBGSurfaceControl->isValid());
// Foreground surface
- mFGSurfaceControl = mComposerClient->createSurface(String8(TEST_FG_SURFACE_NAME), displayWidth,
- displayHeight, PIXEL_FORMAT_RGBA_8888, 0);
+ mFGSurfaceControl =
+ mComposerClient->createSurface(String8(TEST_FG_SURFACE_NAME), resolution.getWidth(),
+ resolution.getHeight(), PIXEL_FORMAT_RGBA_8888, 0);
ASSERT_TRUE(mFGSurfaceControl != nullptr);
ASSERT_TRUE(mFGSurfaceControl->isValid());
diff --git a/services/surfaceflinger/tests/TransactionTestHarnesses.h b/services/surfaceflinger/tests/TransactionTestHarnesses.h
index 5612bb2..040852f 100644
--- a/services/surfaceflinger/tests/TransactionTestHarnesses.h
+++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h
@@ -16,41 +16,10 @@
#ifndef ANDROID_TRANSACTION_TEST_HARNESSES
#define ANDROID_TRANSACTION_TEST_HARNESSES
-/*#include <algorithm>
-#include <chrono>
-#include <cinttypes>
-#include <functional>
-#include <limits>
-#include <ostream>
+#include <ui/DisplayState.h>
-#include <android/native_window.h>
-
-#include <binder/ProcessState.h>
-#include <gui/BufferItemConsumer.h>
-#include <gui/IProducerListener.h>
-#include <gui/ISurfaceComposer.h>
-#include <gui/LayerState.h>
-#include <gui/Surface.h>
-#include <gui/SurfaceComposerClient.h>
-#include <hardware/hwcomposer_defs.h>
-#include <private/android_filesystem_config.h>
-#include <private/gui/ComposerService.h>
-
-#include <ui/DisplayInfo.h>
-
-#include <math.h>
-#include <math/vec3.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "BufferGenerator.h"
-*/
#include "LayerTransactionTest.h"
-/*#include "utils/CallbackUtils.h"
-#include "utils/ColorUtils.h"
-#include "utils/ScreenshotUtils.h"
-#include "utils/TransactionUtils.h"
-*/
+
namespace android {
using android::hardware::graphics::common::V1_1::BufferUsage;
@@ -66,9 +35,14 @@
return mDelegate->screenshot();
case RenderPath::VIRTUAL_DISPLAY:
- const auto mainDisplay = SurfaceComposerClient::getInternalDisplayToken();
- DisplayInfo mainDisplayInfo;
- SurfaceComposerClient::getDisplayInfo(mainDisplay, &mainDisplayInfo);
+ const auto displayToken = SurfaceComposerClient::getInternalDisplayToken();
+
+ ui::DisplayState displayState;
+ SurfaceComposerClient::getDisplayState(displayToken, &displayState);
+
+ DisplayConfig displayConfig;
+ SurfaceComposerClient::getActiveDisplayConfig(displayToken, &displayConfig);
+ const ui::Size& resolution = displayConfig.resolution;
sp<IBinder> vDisplay;
sp<IGraphicBufferProducer> producer;
@@ -77,7 +51,7 @@
BufferQueue::createBufferQueue(&producer, &consumer);
consumer->setConsumerName(String8("Virtual disp consumer"));
- consumer->setDefaultBufferSize(mainDisplayInfo.w, mainDisplayInfo.h);
+ consumer->setDefaultBufferSize(resolution.getWidth(), resolution.getHeight());
itemConsumer = new BufferItemConsumer(consumer,
// Sample usage bits from screenrecord
@@ -90,9 +64,8 @@
SurfaceComposerClient::Transaction t;
t.setDisplaySurface(vDisplay, producer);
t.setDisplayLayerStack(vDisplay, 0);
- t.setDisplayProjection(vDisplay, mainDisplayInfo.orientation,
- Rect(mainDisplayInfo.viewportW, mainDisplayInfo.viewportH),
- Rect(mainDisplayInfo.w, mainDisplayInfo.h));
+ t.setDisplayProjection(vDisplay, displayState.orientation,
+ Rect(displayState.viewport), Rect(resolution));
t.apply();
SurfaceComposerClient::Transaction().apply(true);
BufferItem item;
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 6874f6f..e751496 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -41,7 +41,7 @@
#include <hwbinder/ProcessState.h>
#include <log/log.h>
#include <private/gui/ComposerService.h>
-#include <ui/DisplayInfo.h>
+#include <ui/DisplayConfig.h>
#include <utils/Looper.h>
#include <gmock/gmock.h>
@@ -338,15 +338,16 @@
const auto display = SurfaceComposerClient::getPhysicalDisplayToken(EXTERNAL_DISPLAY);
EXPECT_FALSE(display == nullptr);
- DisplayInfo info;
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
- EXPECT_EQ(200u, info.w);
- EXPECT_EQ(400u, info.h);
- EXPECT_EQ(1e9f / 16'666'666, info.fps);
+ DisplayConfig config;
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ const ui::Size& resolution = config.resolution;
+ EXPECT_EQ(ui::Size(200, 400), resolution);
+ EXPECT_EQ(1e9f / 16'666'666, config.refreshRate);
auto surfaceControl =
- mComposerClient->createSurface(String8("Display Test Surface Foo"), info.w,
- info.h, PIXEL_FORMAT_RGBA_8888, 0);
+ mComposerClient->createSurface(String8("Display Test Surface Foo"),
+ resolution.getWidth(), resolution.getHeight(),
+ PIXEL_FORMAT_RGBA_8888, 0);
EXPECT_TRUE(surfaceControl != nullptr);
EXPECT_TRUE(surfaceControl->isValid());
fillSurfaceRGBA8(surfaceControl, BLUE);
@@ -369,8 +370,8 @@
const auto display = SurfaceComposerClient::getPhysicalDisplayToken(EXTERNAL_DISPLAY);
EXPECT_TRUE(display == nullptr);
- DisplayInfo info;
- EXPECT_NE(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
+ DisplayConfig config;
+ EXPECT_NE(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
}
}
@@ -398,17 +399,18 @@
const auto display = SurfaceComposerClient::getPhysicalDisplayToken(EXTERNAL_DISPLAY);
EXPECT_FALSE(display == nullptr);
- DisplayInfo info;
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
- EXPECT_EQ(200u, info.w);
- EXPECT_EQ(400u, info.h);
- EXPECT_EQ(1e9f / 16'666'666, info.fps);
+ DisplayConfig config;
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ EXPECT_EQ(ui::Size(200, 400), config.resolution);
+ EXPECT_EQ(1e9f / 16'666'666, config.refreshRate);
mFakeComposerClient->clearFrames();
{
+ const ui::Size& resolution = config.resolution;
auto surfaceControl =
- mComposerClient->createSurface(String8("Display Test Surface Foo"), info.w,
- info.h, PIXEL_FORMAT_RGBA_8888, 0);
+ mComposerClient->createSurface(String8("Display Test Surface Foo"),
+ resolution.getWidth(), resolution.getHeight(),
+ PIXEL_FORMAT_RGBA_8888, 0);
EXPECT_TRUE(surfaceControl != nullptr);
EXPECT_TRUE(surfaceControl->isValid());
fillSurfaceRGBA8(surfaceControl, BLUE);
@@ -421,7 +423,7 @@
}
}
- Vector<DisplayInfo> configs;
+ Vector<DisplayConfig> configs;
EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs));
EXPECT_EQ(configs.size(), 2);
@@ -436,27 +438,29 @@
}
for (int i = 0; i < configs.size(); i++) {
- if (configs[i].w == 800u) {
+ const auto& config = configs[i];
+ if (config.resolution.getWidth() == 800) {
EXPECT_EQ(NO_ERROR,
SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
- configs[i].fps,
- configs[i].fps));
+ config.refreshRate,
+ config.refreshRate));
waitForDisplayTransaction();
EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
break;
}
}
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
- EXPECT_EQ(800u, info.w);
- EXPECT_EQ(1600u, info.h);
- EXPECT_EQ(1e9f / 11'111'111, info.fps);
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ EXPECT_EQ(ui::Size(800, 1600), config.resolution);
+ EXPECT_EQ(1e9f / 11'111'111, config.refreshRate);
mFakeComposerClient->clearFrames();
{
+ const ui::Size& resolution = config.resolution;
auto surfaceControl =
- mComposerClient->createSurface(String8("Display Test Surface Foo"), info.w,
- info.h, PIXEL_FORMAT_RGBA_8888, 0);
+ mComposerClient->createSurface(String8("Display Test Surface Foo"),
+ resolution.getWidth(), resolution.getHeight(),
+ PIXEL_FORMAT_RGBA_8888, 0);
EXPECT_TRUE(surfaceControl != nullptr);
EXPECT_TRUE(surfaceControl->isValid());
fillSurfaceRGBA8(surfaceControl, BLUE);
@@ -500,17 +504,18 @@
const auto display = SurfaceComposerClient::getPhysicalDisplayToken(EXTERNAL_DISPLAY);
EXPECT_FALSE(display == nullptr);
- DisplayInfo info;
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
- EXPECT_EQ(800u, info.w);
- EXPECT_EQ(1600u, info.h);
- EXPECT_EQ(1e9f / 16'666'666, info.fps);
+ DisplayConfig config;
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ EXPECT_EQ(ui::Size(800, 1600), config.resolution);
+ EXPECT_EQ(1e9f / 16'666'666, config.refreshRate);
mFakeComposerClient->clearFrames();
{
+ const ui::Size& resolution = config.resolution;
auto surfaceControl =
- mComposerClient->createSurface(String8("Display Test Surface Foo"), info.w,
- info.h, PIXEL_FORMAT_RGBA_8888, 0);
+ mComposerClient->createSurface(String8("Display Test Surface Foo"),
+ resolution.getWidth(), resolution.getHeight(),
+ PIXEL_FORMAT_RGBA_8888, 0);
EXPECT_TRUE(surfaceControl != nullptr);
EXPECT_TRUE(surfaceControl->isValid());
fillSurfaceRGBA8(surfaceControl, BLUE);
@@ -523,7 +528,7 @@
}
}
- Vector<DisplayInfo> configs;
+ Vector<DisplayConfig> configs;
EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs));
EXPECT_EQ(configs.size(), 2);
@@ -537,27 +542,29 @@
}
for (int i = 0; i < configs.size(); i++) {
- if (configs[i].fps == 1e9f / 11'111'111) {
+ const auto& config = configs[i];
+ if (config.refreshRate == 1e9f / 11'111'111) {
EXPECT_EQ(NO_ERROR,
SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
- configs[i].fps,
- configs[i].fps));
+ config.refreshRate,
+ config.refreshRate));
waitForDisplayTransaction();
EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
break;
}
}
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
- EXPECT_EQ(800u, info.w);
- EXPECT_EQ(1600u, info.h);
- EXPECT_EQ(1e9f / 11'111'111, info.fps);
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ EXPECT_EQ(ui::Size(800, 1600), config.resolution);
+ EXPECT_EQ(1e9f / 11'111'111, config.refreshRate);
mFakeComposerClient->clearFrames();
{
+ const ui::Size& resolution = config.resolution;
auto surfaceControl =
- mComposerClient->createSurface(String8("Display Test Surface Foo"), info.w,
- info.h, PIXEL_FORMAT_RGBA_8888, 0);
+ mComposerClient->createSurface(String8("Display Test Surface Foo"),
+ resolution.getWidth(), resolution.getHeight(),
+ PIXEL_FORMAT_RGBA_8888, 0);
EXPECT_TRUE(surfaceControl != nullptr);
EXPECT_TRUE(surfaceControl->isValid());
fillSurfaceRGBA8(surfaceControl, BLUE);
@@ -611,17 +618,18 @@
const auto display = SurfaceComposerClient::getPhysicalDisplayToken(EXTERNAL_DISPLAY);
EXPECT_FALSE(display == nullptr);
- DisplayInfo info;
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
- EXPECT_EQ(800u, info.w);
- EXPECT_EQ(1600u, info.h);
- EXPECT_EQ(1e9f / 16'666'666, info.fps);
+ DisplayConfig config;
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ EXPECT_EQ(ui::Size(800, 1600), config.resolution);
+ EXPECT_EQ(1e9f / 16'666'666, config.refreshRate);
mFakeComposerClient->clearFrames();
{
+ const ui::Size& resolution = config.resolution;
auto surfaceControl =
- mComposerClient->createSurface(String8("Display Test Surface Foo"), info.w,
- info.h, PIXEL_FORMAT_RGBA_8888, 0);
+ mComposerClient->createSurface(String8("Display Test Surface Foo"),
+ resolution.getWidth(), resolution.getHeight(),
+ PIXEL_FORMAT_RGBA_8888, 0);
EXPECT_TRUE(surfaceControl != nullptr);
EXPECT_TRUE(surfaceControl->isValid());
fillSurfaceRGBA8(surfaceControl, BLUE);
@@ -634,7 +642,7 @@
}
}
- Vector<DisplayInfo> configs;
+ Vector<DisplayConfig> configs;
EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs));
EXPECT_EQ(configs.size(), 4);
@@ -648,27 +656,29 @@
}
for (int i = 0; i < configs.size(); i++) {
- if (configs[i].w == 800u && configs[i].fps == 1e9f / 11'111'111) {
+ const auto& config = configs[i];
+ if (config.resolution.getWidth() == 800 && config.refreshRate == 1e9f / 11'111'111) {
EXPECT_EQ(NO_ERROR,
SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
- configs[i].fps,
- configs[i].fps));
+ configs[i].refreshRate,
+ configs[i].refreshRate));
waitForDisplayTransaction();
EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
break;
}
}
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
- EXPECT_EQ(800u, info.w);
- EXPECT_EQ(1600u, info.h);
- EXPECT_EQ(1e9f / 11'111'111, info.fps);
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ EXPECT_EQ(ui::Size(800, 1600), config.resolution);
+ EXPECT_EQ(1e9f / 11'111'111, config.refreshRate);
mFakeComposerClient->clearFrames();
{
+ const ui::Size& resolution = config.resolution;
auto surfaceControl =
- mComposerClient->createSurface(String8("Display Test Surface Foo"), info.w,
- info.h, PIXEL_FORMAT_RGBA_8888, 0);
+ mComposerClient->createSurface(String8("Display Test Surface Foo"),
+ resolution.getWidth(), resolution.getHeight(),
+ PIXEL_FORMAT_RGBA_8888, 0);
EXPECT_TRUE(surfaceControl != nullptr);
EXPECT_TRUE(surfaceControl->isValid());
fillSurfaceRGBA8(surfaceControl, BLUE);
@@ -691,27 +701,29 @@
}
for (int i = 0; i < configs.size(); i++) {
- if (configs[i].fps == 1e9f / 8'333'333) {
+ const auto& config = configs[i];
+ if (config.refreshRate == 1e9f / 8'333'333) {
EXPECT_EQ(NO_ERROR,
SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
- configs[i].fps,
- configs[i].fps));
+ config.refreshRate,
+ config.refreshRate));
waitForDisplayTransaction();
EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
break;
}
}
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
- EXPECT_EQ(1600u, info.w);
- EXPECT_EQ(3200u, info.h);
- EXPECT_EQ(1e9f / 8'333'333, info.fps);
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ EXPECT_EQ(ui::Size(1600, 3200), config.resolution);
+ EXPECT_EQ(1e9f / 8'333'333, config.refreshRate);
mFakeComposerClient->clearFrames();
{
+ const ui::Size& resolution = config.resolution;
auto surfaceControl =
- mComposerClient->createSurface(String8("Display Test Surface Foo"), info.w,
- info.h, PIXEL_FORMAT_RGBA_8888, 0);
+ mComposerClient->createSurface(String8("Display Test Surface Foo"),
+ resolution.getWidth(), resolution.getHeight(),
+ PIXEL_FORMAT_RGBA_8888, 0);
EXPECT_TRUE(surfaceControl != nullptr);
EXPECT_TRUE(surfaceControl->isValid());
fillSurfaceRGBA8(surfaceControl, BLUE);
@@ -734,27 +746,29 @@
}
for (int i = 0; i < configs.size(); i++) {
- if (configs[i].w == 1600 && configs[i].fps == 1e9f / 11'111'111) {
+ const auto& config = configs[i];
+ if (config.resolution.getWidth() == 1600 && config.refreshRate == 1e9f / 11'111'111) {
EXPECT_EQ(NO_ERROR,
SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
- configs[i].fps,
- configs[i].fps));
+ config.refreshRate,
+ config.refreshRate));
waitForDisplayTransaction();
EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
break;
}
}
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
- EXPECT_EQ(1600u, info.w);
- EXPECT_EQ(3200u, info.h);
- EXPECT_EQ(1e9f / 11'111'111, info.fps);
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ EXPECT_EQ(ui::Size(1600, 3200), config.resolution);
+ EXPECT_EQ(1e9f / 11'111'111, config.refreshRate);
mFakeComposerClient->clearFrames();
{
+ const ui::Size& resolution = config.resolution;
auto surfaceControl =
- mComposerClient->createSurface(String8("Display Test Surface Foo"), info.w,
- info.h, PIXEL_FORMAT_RGBA_8888, 0);
+ mComposerClient->createSurface(String8("Display Test Surface Foo"),
+ resolution.getWidth(), resolution.getHeight(),
+ PIXEL_FORMAT_RGBA_8888, 0);
EXPECT_TRUE(surfaceControl != nullptr);
EXPECT_TRUE(surfaceControl->isValid());
fillSurfaceRGBA8(surfaceControl, BLUE);
@@ -787,8 +801,8 @@
const auto display = SurfaceComposerClient::getPhysicalDisplayToken(PRIMARY_DISPLAY);
EXPECT_TRUE(display == nullptr);
- DisplayInfo info;
- auto result = SurfaceComposerClient::getDisplayInfo(display, &info);
+ DisplayConfig config;
+ auto result = SurfaceComposerClient::getActiveDisplayConfig(display, &config);
EXPECT_NE(NO_ERROR, result);
}
@@ -813,12 +827,11 @@
const auto display = SurfaceComposerClient::getPhysicalDisplayToken(PRIMARY_DISPLAY);
EXPECT_FALSE(display == nullptr);
- DisplayInfo info;
- auto result = SurfaceComposerClient::getDisplayInfo(display, &info);
+ DisplayConfig config;
+ auto result = SurfaceComposerClient::getActiveDisplayConfig(display, &config);
EXPECT_EQ(NO_ERROR, result);
- ASSERT_EQ(400u, info.w);
- ASSERT_EQ(200u, info.h);
- EXPECT_EQ(1e9f / 16'666'666, info.fps);
+ ASSERT_EQ(ui::Size(400, 200), config.resolution);
+ EXPECT_EQ(1e9f / 16'666'666, config.refreshRate);
}
}
@@ -968,11 +981,12 @@
const auto display = SurfaceComposerClient::getPhysicalDisplayToken(PRIMARY_DISPLAY);
ASSERT_FALSE(display == nullptr);
- DisplayInfo info;
- ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
+ DisplayConfig config;
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
- mDisplayWidth = info.w;
- mDisplayHeight = info.h;
+ const ui::Size& resolution = config.resolution;
+ mDisplayWidth = resolution.getWidth();
+ mDisplayHeight = resolution.getHeight();
// Background surface
mBGSurfaceControl =
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index c6d8a2e..888e009 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -842,8 +842,8 @@
EXPECT_CALL(*test->mComposer, createLayer(HWC_DISPLAY, _))
.WillOnce(DoAll(SetArgPointee<1>(HWC_LAYER), Return(Error::NONE)));
- auto outputLayer = test->mDisplay->getCompositionDisplay()
- ->injectOutputLayerForTest(layer->getCompositionLayer(), layer);
+ auto outputLayer = test->mDisplay->getCompositionDisplay()->injectOutputLayerForTest(
+ layer->getCompositionEngineLayerFE());
outputLayer->editState().visibleRegion = Region(Rect(0, 0, 100, 100));
outputLayer->editState().outputSpaceVisibleRegion = Region(Rect(0, 0, 100, 100));
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index 68b7a74..d9481be 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -63,7 +63,8 @@
auto createLayer() { return sp<mock::MockLayer>(new mock::MockLayer(mFlinger.flinger())); }
- RefreshRateConfigs mConfigs{{
+ RefreshRateConfigs mConfigs{true,
+ {
RefreshRateConfigs::InputConfig{HwcConfigIndexType(0),
HwcConfigGroupType(0),
LO_FPS_PERIOD},
@@ -84,7 +85,7 @@
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_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
@@ -113,7 +114,7 @@
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_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
@@ -137,15 +138,15 @@
EXPECT_CALL(*layer1, isVisible()).WillRepeatedly(Return(true));
EXPECT_CALL(*layer1, getFrameSelectionPriority()).WillRepeatedly(Return(1));
- EXPECT_CALL(*layer1, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer1, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_CALL(*layer2, isVisible()).WillRepeatedly(Return(true));
EXPECT_CALL(*layer2, getFrameSelectionPriority()).WillRepeatedly(Return(1));
- EXPECT_CALL(*layer2, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer2, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_CALL(*layer3, isVisible()).WillRepeatedly(Return(true));
EXPECT_CALL(*layer3, getFrameSelectionPriority()).WillRepeatedly(Return(1));
- EXPECT_CALL(*layer3, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer3, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
nsecs_t time = mTime;
EXPECT_EQ(3, layerCount());
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
index 8d39dca..bb3bbad 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
@@ -34,7 +34,6 @@
class LayerHistoryTestV2 : public testing::Test {
protected:
- static constexpr auto FREQUENT_LAYER_WINDOW_SIZE = LayerInfoV2::FREQUENT_LAYER_WINDOW_SIZE;
static constexpr auto PRESENT_TIME_HISTORY_SIZE = LayerInfoV2::HISTORY_SIZE;
static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS = LayerInfoV2::MAX_FREQUENT_LAYER_PERIOD_NS;
@@ -72,7 +71,8 @@
auto createLayer() { return sp<mock::MockLayer>(new mock::MockLayer(mFlinger.flinger())); }
- RefreshRateConfigs mConfigs{{
+ RefreshRateConfigs mConfigs{true,
+ {
RefreshRateConfigs::InputConfig{HwcConfigIndexType(0),
HwcConfigGroupType(0),
LO_FPS_PERIOD},
@@ -84,7 +84,6 @@
TestableScheduler* const mScheduler{new TestableScheduler(mConfigs, true)};
TestableSurfaceFlinger mFlinger;
- const nsecs_t mTime = systemTime();
};
namespace {
@@ -92,31 +91,30 @@
TEST_F(LayerHistoryTestV2, oneLayer) {
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
+ const nsecs_t time = systemTime();
+
// No layers returned if no layers are active.
- EXPECT_TRUE(history().summarize(mTime).empty());
+ EXPECT_TRUE(history().summarize(time).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());
- const auto expectedType = (i + 1 < FREQUENT_LAYER_WINDOW_SIZE)
- ? LayerHistory::LayerVoteType::Min
- : LayerHistory::LayerVoteType::Max;
- EXPECT_EQ(expectedType, history().summarize(mTime)[0].vote);
+ history().record(layer.get(), 0, time);
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[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);
+ history().record(layer.get(), 0, time);
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
}
}
@@ -124,34 +122,36 @@
TEST_F(LayerHistoryTestV2, oneInvisibleLayer) {
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
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());
+ nsecs_t time = systemTime();
+
+ history().record(layer.get(), 0, time);
+ auto summary = history().summarize(time);
+ ASSERT_EQ(1, history().summarize(time).size());
// Layer is still considered inactive so we expect to get Min
- EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(mTime)[0].vote);
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(false));
- summary = history().summarize(mTime);
- EXPECT_TRUE(history().summarize(mTime).empty());
+ summary = history().summarize(time);
+ EXPECT_TRUE(history().summarize(time).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_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
- nsecs_t time = mTime;
+ nsecs_t time = systemTime();
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer.get(), time, time);
time += LO_FPS_PERIOD;
@@ -167,14 +167,14 @@
TEST_F(LayerHistoryTestV2, oneLayerNoVote) {
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::NoVote);
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
- nsecs_t time = mTime;
+ nsecs_t time = systemTime();
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer.get(), time, time);
time += HI_FPS_PERIOD;
@@ -194,14 +194,14 @@
TEST_F(LayerHistoryTestV2, oneLayerMinVote) {
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::Min);
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
- nsecs_t time = mTime;
+ nsecs_t time = systemTime();
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer.get(), time, time);
time += HI_FPS_PERIOD;
@@ -222,14 +222,14 @@
TEST_F(LayerHistoryTestV2, oneLayerMaxVote) {
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::Max);
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
- nsecs_t time = mTime;
+ nsecs_t time = systemTime();
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer.get(), time, time);
time += LO_FPS_PERIOD;
@@ -250,19 +250,53 @@
TEST_F(LayerHistoryTestV2, oneLayerExplicitVote) {
auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(73.4f));
+ EXPECT_CALL(*layer, getFrameRate())
+ .WillRepeatedly(
+ Return(Layer::FrameRate(73.4f, Layer::FrameRateCompatibility::Default)));
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
- nsecs_t time = mTime;
+ nsecs_t time = systemTime();
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_EQ(LayerHistory::LayerVoteType::ExplicitDefault, 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, oneLayerExplicitExactVote) {
+ auto layer = createLayer();
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameRate())
+ .WillRepeatedly(Return(
+ Layer::FrameRate(73.4f, Layer::FrameRateCompatibility::ExactOrMultiple)));
+
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+
+ nsecs_t time = systemTime();
+ 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::ExplicitExactOrMultiple,
+ history().summarize(time)[0].vote);
EXPECT_FLOAT_EQ(73.4f, history().summarize(time)[0].desiredRefreshRate);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
@@ -282,15 +316,15 @@
auto layer3 = createLayer();
EXPECT_CALL(*layer1, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer1, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer1, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_CALL(*layer2, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer2, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer2, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_CALL(*layer3, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer3, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer3, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
- nsecs_t time = mTime;
+ nsecs_t time = systemTime();
EXPECT_EQ(3, layerCount());
EXPECT_EQ(0, activeLayerCount());
@@ -318,7 +352,7 @@
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);
+ ASSERT_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));
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index cd9f2b1..7c1ecea 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -74,14 +74,26 @@
std::vector<RefreshRateConfigs::InputConfig> configs{
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
+ std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+ ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+}
+
+TEST_F(RefreshRateConfigsTest, oneDeviceConfig_SwitchingNotSupported) {
+ std::vector<RefreshRateConfigs::InputConfig> configs{
+ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}}};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/false, configs,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+ ASSERT_FALSE(refreshRateConfigs->refreshRateSwitchingSupported());
}
TEST_F(RefreshRateConfigsTest, invalidPolicy) {
std::vector<RefreshRateConfigs::InputConfig> configs{
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
+ std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
ASSERT_LT(refreshRateConfigs->setPolicy(HwcConfigIndexType(10), 60, 60, nullptr), 0);
ASSERT_LT(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 20, 40, nullptr), 0);
}
@@ -91,7 +103,10 @@
{{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>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
+ std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
const auto minRate = refreshRateConfigs->getMinRefreshRate();
const auto performanceRate = refreshRateConfigs->getMaxRefreshRate();
@@ -113,8 +128,10 @@
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_1, VSYNC_90}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
+ std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+ ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
const auto minRate = refreshRateConfigs->getMinRefreshRateByPolicy();
const auto performanceRate = refreshRateConfigs->getMaxRefreshRate();
const auto minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy();
@@ -128,6 +145,7 @@
ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 60, 90, nullptr), 0);
refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
+ ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
const auto minRate90 = refreshRateConfigs->getMinRefreshRateByPolicy();
const auto performanceRate90 = refreshRateConfigs->getMaxRefreshRateByPolicy();
@@ -143,8 +161,9 @@
{{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>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
-
+ std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+ ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
auto minRate = refreshRateConfigs->getMinRefreshRateByPolicy();
auto performanceRate = refreshRateConfigs->getMaxRefreshRateByPolicy();
@@ -155,6 +174,7 @@
ASSERT_EQ(expectedPerformanceConfig, performanceRate);
ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 60, 60, nullptr), 0);
+ ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
auto minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy();
auto performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy();
@@ -167,7 +187,8 @@
{{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>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
+ std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
{
auto current = refreshRateConfigs->getCurrentRefreshRate();
EXPECT_EQ(current.configId, HWC_CONFIG_ID_60);
@@ -191,7 +212,10 @@
{{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>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
+ 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};
@@ -252,7 +276,10 @@
{{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>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
+ 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};
@@ -360,7 +387,10 @@
{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>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
+ 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};
@@ -400,7 +430,10 @@
{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>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
+ 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};
@@ -432,12 +465,87 @@
EXPECT_EQ(expected72Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
}
+TEST_F(RefreshRateConfigsTest,
+ twoDeviceConfigs_getRefreshRateForContentV2_30_60_90_120_DifferentTypes) {
+ 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);
+
+ 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", 72};
+ 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::ExplicitDefault;
+ lr2.desiredRefreshRate = 60.0f;
+ lr2.vote = LayerVoteType::Heuristic;
+ EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr2.desiredRefreshRate = 60.0f;
+ lr2.vote = LayerVoteType::Heuristic;
+ EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr2.desiredRefreshRate = 60.0f;
+ lr2.vote = LayerVoteType::ExplicitDefault;
+ EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr2.desiredRefreshRate = 90.0f;
+ lr2.vote = LayerVoteType::Heuristic;
+ EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::ExplicitDefault;
+ lr2.desiredRefreshRate = 90.0f;
+ lr2.vote = LayerVoteType::Heuristic;
+ EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::Heuristic;
+ lr2.desiredRefreshRate = 90.0f;
+ lr2.vote = LayerVoteType::ExplicitDefault;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr2.desiredRefreshRate = 90.0f;
+ lr2.vote = LayerVoteType::ExplicitDefault;
+ EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::ExplicitDefault;
+ lr2.desiredRefreshRate = 90.0f;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
+ EXPECT_EQ(expected90Config, 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>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
+ 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};
@@ -475,7 +583,10 @@
{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>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
+ 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};
@@ -514,7 +625,10 @@
{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>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
+ 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};
@@ -535,7 +649,7 @@
EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
lr1.vote = LayerVoteType::Min;
- lr2.vote = LayerVoteType::Explicit;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 24.0f;
EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
@@ -545,7 +659,7 @@
EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
lr1.vote = LayerVoteType::Max;
- lr2.vote = LayerVoteType::Explicit;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 60.0f;
EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
@@ -557,7 +671,7 @@
lr1.vote = LayerVoteType::Heuristic;
lr1.desiredRefreshRate = 30.0f;
- lr2.vote = LayerVoteType::Explicit;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 45.0f;
EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
}
@@ -567,7 +681,10 @@
{{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>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
+ 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};
@@ -576,7 +693,7 @@
auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
auto& lr = layers[0];
- lr.vote = LayerVoteType::Explicit;
+ lr.vote = LayerVoteType::ExplicitExactOrMultiple;
for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) {
lr.desiredRefreshRate = fps;
const auto& refreshRate = refreshRateConfigs->getRefreshRateForContentV2(layers);
@@ -590,7 +707,10 @@
{{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>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
+ 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};
@@ -602,13 +722,13 @@
lr1.vote = LayerVoteType::Heuristic;
lr1.desiredRefreshRate = 60.0f;
- lr2.vote = LayerVoteType::Explicit;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 90.0f;
EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(layers));
lr1.vote = LayerVoteType::Heuristic;
lr1.desiredRefreshRate = 90.0f;
- lr2.vote = LayerVoteType::Explicit;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 60.0f;
EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(layers));
}
@@ -618,7 +738,10 @@
{{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>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
+ 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};
@@ -630,13 +753,13 @@
lr1.vote = LayerVoteType::Heuristic;
lr1.desiredRefreshRate = 60.0f;
- lr2.vote = LayerVoteType::Explicit;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 90.0f;
EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
lr1.vote = LayerVoteType::Heuristic;
lr1.desiredRefreshRate = 90.0f;
- lr2.vote = LayerVoteType::Explicit;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 60.0f;
EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
}
@@ -656,7 +779,10 @@
{{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>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
+ 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};
@@ -665,7 +791,7 @@
auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
auto& lr = layers[0];
- lr.vote = LayerVoteType::Explicit;
+ lr.vote = LayerVoteType::ExplicitExactOrMultiple;
for (float fps = 75.0f; fps < 100.0f; fps += 0.1f) {
lr.desiredRefreshRate = fps;
const auto& refreshRate = refreshRateConfigs->getRefreshRateForContentV2(layers);
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
index 18d6bd2..8e07c79 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -47,8 +47,8 @@
~RefreshRateStatsTest();
void init(const std::vector<RefreshRateConfigs::InputConfig>& configs) {
- mRefreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(configs, /*currentConfig=*/CONFIG_ID_0);
+ mRefreshRateConfigs = std::make_unique<RefreshRateConfigs>(
+ /*refreshRateSwitching=*/true, configs, /*currentConfig=*/CONFIG_ID_0);
mRefreshRateStats =
std::make_unique<RefreshRateStats>(*mRefreshRateConfigs, mTimeStats,
/*currentConfigId=*/CONFIG_ID_0,
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 89002a8..82a00ee 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -73,7 +73,8 @@
std::vector<scheduler::RefreshRateConfigs::InputConfig> configs{
{{HwcConfigIndexType(0), HwcConfigGroupType(0), 16666667}}};
mRefreshRateConfigs = std::make_unique<
- scheduler::RefreshRateConfigs>(configs, /*currentConfig=*/HwcConfigIndexType(0));
+ scheduler::RefreshRateConfigs>(/*refreshRateSwitching=*/false, configs,
+ /*currentConfig=*/HwcConfigIndexType(0));
mScheduler = std::make_unique<TestableScheduler>(*mRefreshRateConfigs, false);
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index be233bb..64838ca 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -17,7 +17,6 @@
#pragma once
#include <compositionengine/Display.h>
-#include <compositionengine/Layer.h>
#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/OutputLayer.h>
#include <compositionengine/impl/CompositionEngine.h>
@@ -203,7 +202,8 @@
std::vector<scheduler::RefreshRateConfigs::InputConfig> configs{
{{HwcConfigIndexType(0), HwcConfigGroupType(0), 16666667}}};
mFlinger->mRefreshRateConfigs = std::make_unique<
- scheduler::RefreshRateConfigs>(configs, /*currentConfig=*/HwcConfigIndexType(0));
+ scheduler::RefreshRateConfigs>(/*refreshRateSwitching=*/false, configs,
+ /*currentConfig=*/HwcConfigIndexType(0));
mFlinger->mRefreshRateStats = std::make_unique<
scheduler::RefreshRateStats>(*mFlinger->mRefreshRateConfigs, *mFlinger->mTimeStats,
/*currentConfig=*/HwcConfigIndexType(0),
@@ -251,7 +251,7 @@
void setLayerSidebandStream(sp<Layer> layer, sp<NativeHandle> sidebandStream) {
layer->mDrawingState.sidebandStream = sidebandStream;
layer->mSidebandStream = sidebandStream;
- layer->getCompositionLayer()->editFEState().sidebandStream = sidebandStream;
+ layer->editCompositionState()->sidebandStream = sidebandStream;
}
void setLayerCompositionType(sp<Layer> layer, HWC2::Composition type) {
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index 6744f9f..91a40d0 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -37,6 +37,7 @@
using namespace android::surfaceflinger;
using namespace google::protobuf;
+using namespace std::chrono_literals;
namespace android {
namespace {
@@ -148,30 +149,31 @@
FakeStatsEventDelegate() = default;
~FakeStatsEventDelegate() override = default;
- struct stats_event* addStatsEventToPullData(pulled_stats_event_list*) override {
+ struct AStatsEvent* addStatsEventToPullData(AStatsEventList*) override {
return mEvent;
}
- void registerStatsPullAtomCallback(int32_t atom_tag, stats_pull_atom_callback_t callback,
- pull_atom_metadata*, void* cookie) override {
+ void registerStatsPullAtomCallback(int32_t atom_tag,
+ AStatsManager_PullAtomCallback callback,
+ AStatsManager_PullAtomMetadata*, void* cookie) override {
mAtomTags.push_back(atom_tag);
mCallback = callback;
mCookie = cookie;
}
- status_pull_atom_return_t makePullAtomCallback(int32_t atom_tag, void* cookie) {
+ AStatsManager_PullAtomCallbackReturn 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*));
+ MOCK_METHOD2(statsEventSetAtomId, void(AStatsEvent*, uint32_t));
+ MOCK_METHOD2(statsEventWriteInt64, void(AStatsEvent*, int64_t));
+ MOCK_METHOD2(statsEventWriteString8, void(AStatsEvent*, const char*));
+ MOCK_METHOD3(statsEventWriteByteArray, void(AStatsEvent*, const uint8_t*, size_t));
+ MOCK_METHOD1(statsEventBuild, void(AStatsEvent*));
- struct stats_event* mEvent = stats_event_obtain();
+ AStatsEvent* mEvent = AStatsEvent_obtain();
std::vector<int32_t> mAtomTags;
- stats_pull_atom_callback_t mCallback = nullptr;
+ AStatsManager_PullAtomCallback mCallback = nullptr;
void* mCookie = nullptr;
};
FakeStatsEventDelegate* mDelegate = new FakeStatsEventDelegate;
@@ -359,6 +361,45 @@
EXPECT_THAT(result, HasSubstr(expectedResult));
}
+TEST_F(TimeStatsTest, canAverageFrameDuration) {
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+ mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+ mTimeStats
+ ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
+ .count());
+ mTimeStats
+ ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(16ms)
+ .count());
+
+ const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+ EXPECT_THAT(result, HasSubstr("averageFrameDuration = 10.000 ms"));
+}
+
+TEST_F(TimeStatsTest, canAverageRenderEngineTimings) {
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+ mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms)
+ .count(),
+ std::make_shared<FenceTime>(
+ std::chrono::duration_cast<
+ std::chrono::nanoseconds>(3ms)
+ .count()));
+
+ mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(4ms)
+ .count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(8ms)
+ .count());
+
+ // Push a dummy present fence to trigger flushing the RenderEngine timings.
+ mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+ mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(
+ std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count()));
+
+ const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+ EXPECT_THAT(result, HasSubstr("averageRenderEngineTiming = 3.000 ms"));
+}
+
TEST_F(TimeStatsTest, canInsertGlobalPresentToPresent) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
@@ -391,8 +432,6 @@
TEST_F(TimeStatsTest, canInsertGlobalFrameDuration) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
- using namespace std::chrono_literals;
-
mTimeStats->setPowerMode(HWC_POWER_MODE_OFF);
mTimeStats
->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count(),
@@ -416,8 +455,6 @@
TEST_F(TimeStatsTest, canInsertGlobalRenderEngineTiming) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
- using namespace std::chrono_literals;
-
mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms)
.count(),
std::make_shared<FenceTime>(
@@ -673,7 +710,6 @@
ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionFrames());
ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL));
- using namespace std::chrono_literals;
mTimeStats
->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(3ms).count(),
std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
@@ -703,14 +739,27 @@
EXPECT_EQ(0, globalProto.stats_size());
}
-TEST_F(TimeStatsTest, canClearClientCompositionReusedFrames) {
- // this stat is not in the proto so verify by checking the string dump
+TEST_F(TimeStatsTest, canClearDumpOnlyTimeStats) {
+ // These stats are 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());
+ mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+ mTimeStats
+ ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(5ms)
+ .count());
+ mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(4ms)
+ .count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
+ .count());
+ mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(
+ std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count()));
EXPECT_TRUE(inputCommand(InputCommand::CLEAR, FMT_STRING).empty());
const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
EXPECT_THAT(result, HasSubstr("clientCompositionReusedFrames = 0"));
+ EXPECT_THAT(result, HasSubstr("averageFrameDuration = 0.000 ms"));
+ EXPECT_THAT(result, HasSubstr("averageRenderEngineTiming = 0.000 ms"));
}
TEST_F(TimeStatsTest, canDumpWithMaxLayers) {
@@ -787,7 +836,7 @@
EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 2));
EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
}
- EXPECT_EQ(STATS_PULL_SUCCESS,
+ EXPECT_EQ(AStatsManager_PULL_SUCCESS,
mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
mDelegate->mCookie));
@@ -908,7 +957,7 @@
expectedPostToAcquire.size()));
EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
}
- EXPECT_EQ(STATS_PULL_SUCCESS,
+ EXPECT_EQ(AStatsManager_PULL_SUCCESS,
mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
mDelegate->mCookie));
@@ -942,7 +991,7 @@
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,
+ EXPECT_EQ(AStatsManager_PULL_SUCCESS,
mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
mDelegate->mCookie));
}
@@ -983,7 +1032,7 @@
EXPECT_CALL(*mDelegate, statsEventWriteByteArray(mDelegate->mEvent, _, _))
.Times(AnyNumber());
}
- EXPECT_EQ(STATS_PULL_SUCCESS,
+ EXPECT_EQ(AStatsManager_PULL_SUCCESS,
mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
mDelegate->mCookie));
}
@@ -1023,7 +1072,7 @@
EXPECT_CALL(*mDelegate, statsEventWriteByteArray(mDelegate->mEvent, _, _))
.Times(AnyNumber());
}
- EXPECT_EQ(STATS_PULL_SUCCESS,
+ EXPECT_EQ(AStatsManager_PULL_SUCCESS,
mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
mDelegate->mCookie));
}
@@ -1055,7 +1104,7 @@
.Times(1);
EXPECT_CALL(*mDelegate,
statsEventWriteString8(mDelegate->mEvent, StrEq(genLayerName(LAYER_ID_1).c_str())));
- EXPECT_EQ(STATS_PULL_SUCCESS,
+ EXPECT_EQ(AStatsManager_PULL_SUCCESS,
mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
mDelegate->mCookie));
}
diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
index 494e73d..e2f6abd 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
@@ -31,7 +31,7 @@
MOCK_METHOD0(getFrameSelectionPriority, int32_t());
MOCK_CONST_METHOD0(isVisible, bool());
MOCK_METHOD0(createClone, sp<Layer>());
- MOCK_CONST_METHOD0(getFrameRate, std::optional<float>());
+ MOCK_CONST_METHOD0(getFrameRate, FrameRate());
};
} // namespace android::mock
diff --git a/services/surfaceflinger/tests/utils/CallbackUtils.h b/services/surfaceflinger/tests/utils/CallbackUtils.h
index 4e2b7c3..1318deb 100644
--- a/services/surfaceflinger/tests/utils/CallbackUtils.h
+++ b/services/surfaceflinger/tests/utils/CallbackUtils.h
@@ -121,8 +121,10 @@
void verifySurfaceControlStats(const SurfaceControlStats& surfaceControlStats,
nsecs_t latchTime) const {
- const auto& [surfaceControl, acquireTime, previousReleaseFence, transformHint] =
- surfaceControlStats;
+ const auto&
+ [surfaceControl, latch, acquireTime, presentFence, previousReleaseFence,
+ transformHint,
+ frameEvents] = surfaceControlStats;
ASSERT_EQ(acquireTime > 0, mBufferResult == ExpectedResult::Buffer::ACQUIRED)
<< "bad acquire time";